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

Compare commits

..

679 Commits

Author SHA1 Message Date
cmpilato
3af8715ce8 Tag the 1.1.12 final release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.1.12@2665 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-03 14:32:34 +00:00
cmpilato
97c5a82b7b Let's release 1.1.12 today.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2664 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-03 14:27:51 +00:00
cmpilato
21bd391d62 Document a missing template data item (patch_href).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2663 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-03 14:22:25 +00:00
cmpilato
9d1476ef1d Merge from trunk r2657, whose log message read like so:
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.)

Also:

* CHANGES:
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2658 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-31 21:42:38 +00:00
cmpilato
151fcd05e6 Merge from trunk r2653, which did the following:
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/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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2654 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-28 19:30:36 +00:00
cmpilato
22400ddcfb * docs/template-authoring-guide.html
Update <title> and <h1> to reflect that this document is for ViewVC
  1.1, not 1.0.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2636 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-21 14:02:23 +00:00
cmpilato
ae55530edc Record the change made in r2630.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2631 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-17 20:06:02 +00:00
cmpilato
112700a12c * lib/sapi.py
(WsgiServer.escape): Remove as unnecessary and, indeed, incorrect
    per issue #454.

Reported by: Ennio Zarlenga <wzzxo{__AT__}yahoo.fr>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2630 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-17 20:04:07 +00:00
cmpilato
cecffecf39 Merge from trunk r2609 (fixed pointer to Subversion website).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2610 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-04 15:00:01 +00:00
cmpilato
bdac8697fe Merge from trunk r2599:
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/branches/1.1.x@2600 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-30 19:11:27 +00:00
cmpilato
3d9404b67d Merge from trunk r2597, whose log message read like so:
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.)

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2598 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-30 15:50:31 +00:00
cmpilato
7c50f55153 Merge from trunk r2593:
* 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/branches/1.1.x@2594 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-14 17:54:10 +00:00
cmpilato
368e4dc360 Merge from trunk r2591, which added to viewvc.conf.dist descriptions
of the various optionally "allowed_views".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2592 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-07 17:44:18 +00:00
cmpilato
964d8bb5f9 Merge from trunk r2588, whose log message went a little som'thin' like this:
* 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/branches/1.1.x@2589 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-07-01 17:58:19 +00:00
cmpilato
846e8e46c5 Merge from trunk r2586, whose log message read like so:
(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/branches/1.1.x@2587 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-06-23 15:25:59 +00:00
cmpilato
75c719bcde Merge from trunk r2405:
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.)
   
and r2584:

   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>

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2585 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-06-23 15:14:57 +00:00
cmpilato
fc8793bf15 Merge from trunk r2582 which contained only doc tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2583 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-06-14 13:31:35 +00:00
cmpilato
65935c40fd Merge from trunk r2580, whose log message read like so:
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 '$'

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2581 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-06-06 20:05:27 +00:00
cmpilato
a30d0b44cc Merge from trunk r2577, whose log message read like so:
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.

Also:

* CHANGES
  Record this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2578 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-27 19:00:20 +00:00
cmpilato
fded8462d2 Add placeholder for 1.1.12 changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2576 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-17 12:50:37 +00:00
cmpilato
b1095ac763 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2575 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-17 12:38:54 +00:00
cmpilato
e54399a169 Let's try to roll 1.1.11 today, shall we?
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2572 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-17 12:23:20 +00:00
cmpilato
4cc0db75be Merge from trunk r2569 and r2570, which just updated some copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2571 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-17 12:21:27 +00:00
cmpilato
74a9cbb2a0 Minor wording, spelling, and ordering tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2568 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-17 11:49:31 +00:00
cmpilato
390e337a8e * bin/standalone.py
(main): Was cli().  Caller(s) updated.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2567 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 19:01:48 +00:00
cmpilato
ecdac77d5f Merge from trunk r2565, whose modified-per-conflict-resolution log
message might read something like this:

   Add '--help' option to standalone.py.
   
   * bin/standalone.py
     (usage, badusage): New functions.
     (cli): 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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2566 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 19:01:05 +00:00
cmpilato
79158c2ee7 Merge from trunk r2559-2563, which is a bunch of tweaks to the
standalone.py usage message and options handling.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2564 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 13:50:05 +00:00
cmpilato
96fdfbdbcf Merge from trunk r2557, whose log message read like so:
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).

Also:

* CHANGES
  Record this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2558 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-05 14:39:22 +00:00
cmpilato
361538da21 Merge from trunk r2555, whose log message read like so:
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>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2556 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-21 16:06:23 +00:00
cmpilato
6250d4134b Merge some spelling fixes from trunk's r2553 here.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2554 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-20 15:02:08 +00:00
cmpilato
8589949521 Merge from trunk r2550 and r2551, whose combined log messages might
read like so:

   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.GetCommitsTable): New helper.
     (CheckinDatabase.AddCommit, CheckinDatabase.CheckCommit,
      CheckinDatabase.sql_delete): Use new GetCommitsTable() helper
       instead of hard-coding the version-specific selection of the
       commits table.
     (CheckinDatabase.CreateSQLQueryString): Add 'detect_leftover'
       parameter, used internally to check for a reached query limit.
       Also, use new GetCommitsTable() helper.
     (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.
   
   * conf/viewvc.conf.dist
     (row_limit, rss_row_limit): Make it clear what exactly is getting
       limited here.

Also:

* CHANGES:
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2552 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-20 14:56:39 +00:00
cmpilato
f12e262fa5 Merge from trunk r2547, whose log message read like so:
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.

Also:

* CHANGES
  Note this change, referring to it as a 'security fix' due to the
  ramifications of allowing folks to query your potentially monstrous
  database while ignoring your configured response set limits.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2548 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-19 20:44:05 +00:00
cmpilato
f379070697 Merge from trunk r2545, whose log message read something like this:
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().

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2546 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-01 17:02:07 +00:00
cmpilato
d47fc0ff3b Merge from trunk r2543 (with some tweaks to use the 'string' module
functions), whose log message looks like so:

  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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2544 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-01 14:43:01 +00:00
cmpilato
f2b6f0ba86 Merge from trunk r2541, whose log message read like so:
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().

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2542 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-29 16:41:09 +00:00
cmpilato
ddbe150be1 Merge from trunk r2538, which did a little something like this:
* 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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2539 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-15 20:42:42 +00:00
cmpilato
6b5ed7c857 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2537 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-15 16:37:38 +00:00
cmpilato
391f7d8237 Let's get 1.1.10 out today.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2534 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-15 14:57:50 +00:00
cmpilato
141cf5ff10 * CHANGES
Tweak description of a change to not leave room for interpretation that
  the bug was a security vulnerability.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2533 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-15 14:56:15 +00:00
cmpilato
bfe148eb45 Merge from trunk r2531, whose log message read like so:
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.

Also:

* CHANGES
  Note this change, sadly confessing to introducing a regression.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2532 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-11 20:22:58 +00:00
cmpilato
6fb28f2198 Add some helpful URLs to the release instructions. (Merged /trunk:2529.)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2530 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 20:02:37 +00:00
cmpilato
02cc53d34b Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2528 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 19:56:28 +00:00
cmpilato
5928918da4 Merge from trunk r2524, a bump in copyright years.
(Also includes an accidental commit to CHANGES naming today as the
1.1.9 release date.  Which sounds good.  What say you?)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2525 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 19:27:50 +00:00
cmpilato
2e9f84427c Merge from trunk r2522:
* conf/viewvc.conf.dist (log_pagesextra): Set value to match defaults.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2523 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 18:28:55 +00:00
cmpilato
df599031a0 Merge from trunk r2519:
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/branches/1.1.x@2520 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 16:57:47 +00:00
cmpilato
6311c93298 Merge from trunk r2517, whose log message might be interpreted like so:
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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2518 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 15:29:11 +00:00
cmpilato
b982cccbcd Merge from trunk r2514, whose log message read like so:
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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2516 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-17 16:12:54 +00:00
cmpilato
33b8224714 Minor wording tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2515 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-17 16:11:45 +00:00
cmpilato
2f05f570b1 Merge from trunk r2512 which looked a little somethin' like this:
* 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.

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2513 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-16 20:34:37 +00:00
cmpilato
d737657e1d Merge from trunk r2509, whose log message read like so:
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.)

Also:

* CHANGES:
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2510 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-14 16:00:40 +00:00
cmpilato
3d5294635e Merge from trunk r2507, which is just some code re-org business:
* 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/branches/1.1.x@2508 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-11 21:18:11 +00:00
cmpilato
75c3fc2346 Merge from trunk r2505, which did something like this:
* lib/vcauth/svnauthz/__init__.py
     (ViewVCAuthorizer._get_paths_for_root): Trap and return a cleaned-up
       error when the authzfile isn't parse-able.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2506 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-11 16:57:52 +00:00
cmpilato
80bce159af Clarify that Python 3.x is not yet supported. (Merged /trunk:r2502)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2503 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-07 14:49:01 +00:00
cmpilato
7ff9b84ee1 Merge from trunk r2500, whose log message read like so:
* lib/vclib/svn/svn_ra.py
     (client_log): Check for the correct exception.
   
   Reported by: Phil Jeary <Phil.Jeary@dovetailservices.com>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2501 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-01-04 19:28:10 +00:00
cmpilato
b6acd3c114 Merge from trunk r2498, whose log message read like so (after I corrected it. twice.):
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.

Also:

* CHANGES
  Record this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2499 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-09 17:14:20 +00:00
cmpilato
fa5d40caa3 Merge from trunk r2496, whose log message read like so:
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.

Also:

* CHANGES
  Record this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2497 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-09 16:22:05 +00:00
cmpilato
a9cbd4c6a6 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2488 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-02 20:59:12 +00:00
cmpilato
882cdaa46b Let's get 1.1.8 out today, m'kay?
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2485 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-02 20:46:06 +00:00
cmpilato
58e64cb28d Minor tweak to the release process notes. (Merged /trunk:2483)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2484 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-02 20:38:43 +00:00
cmpilato
779e67653b Re-do a bit of conflict resolution from r2479 to reduce release-to-release
delta.

* bin/standalone.py
  (main): Describe --htpasswd-file before --gui now.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2482 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-02 20:34:29 +00:00
cmpilato
0381a772b7 Merge from trunk r2480, whose log message read like so:
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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2481 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-30 21:13:17 +00:00
cmpilato
048b2c8033 Merge from trunk r2478, whose log message read like so at the time:
* 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.

Also:

* CHANGES
  Update a change item to reflect the new state of code 'round these parts.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2479 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-30 18:26:44 +00:00
cmpilato
e354ab302c Merge from trunk r2476, whose log message read a bit like this:
* 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/branches/1.1.x@2477 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-30 16:44:16 +00:00
cmpilato
5f931c6cf1 Merge from trunk r2473, whose log message read like so:
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.

Also:

* CHANGES
  Note this fix, and tweak the announcement of Basic authn support for
  standalone.py to note "Unix only".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2474 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-16 16:16:09 +00:00
cmpilato
576837351a Merge from trunk r2471, whose log message read like so:
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().

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2472 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-10-05 15:04:32 +00:00
cmpilato
6084ccf877 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2468 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 18:49:00 +00:00
cmpilato
514da91629 Let's release 1.1.7 today, shall we?
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2465 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 18:21:15 +00:00
cmpilato
d2c8bb9878 Merge from trunk r2463, which bumps some copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2464 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 18:20:01 +00:00
cmpilato
fe274e9b9c Merge from trunk r2458, r2459, and r2460, whose combined log messages
might read like so:

   Allow users to tell the query script where ViewVC is located while
   still generating the same defaults as before.
   
   Also, fix the query script's WSGI and FastCGI deployments.
   
   * 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.
   
   * 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.
   
   * 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.

Also:

* CHANGES
  Note these changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2462 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 15:31:52 +00:00
cmpilato
6603a67a91 * CHANGES
Tweak change description.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2461 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 15:27:55 +00:00
cmpilato
b50de1c92e Merge from trunk r2454 and r2455, whose log messages contained the
following:

   * lib/vclib/svn/svn_repos.py
     (_split_revprops): Special-case the handling of empty input.
   
   * lib/viewvc.py
     (_re_rewrite_svnrevref): Wrap the regexp with word boundaries.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2456 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-08 18:28:25 +00:00
cmpilato
dfd8dc82f6 Merge from trunk r2452, some release procedure tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2453 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-08 17:14:44 +00:00
cmpilato
1a942d1062 Merge from trunk r2446.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2449 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 19:22:26 +00:00
cmpilato
289a78eb99 Merge from trunk r2444, whose log message read like so:
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.)
   
Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2447 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 19:20:22 +00:00
cmpilato
2897763020 Merge some typo fixes from trunk (r2441, r2442).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2443 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 15:41:48 +00:00
cmpilato
47886423e5 Merge from trunk r2439, whose log message said a little somethin' like
this:

   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().

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2440 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 15:20:10 +00:00
cmpilato
0890821839 Merge from trunk r2435, whose log message contained the following:
* lib/vclib/svn/svn_repos.py
     (BlameSource.__init__): Use client.create_context() instead of
       client.ctx_t() to avoid "NULL proxy object pool" error.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2436 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-03 16:21:25 +00:00
cmpilato
2903389d3e Merge from trunk r2430, whose log message rock opera production had
the following lyrics:

   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().

Also:

* CHANGES
  Record this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2431 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-25 20:18:46 +00:00
cmpilato
5bdea369e8 Merge from trunk r2428, whose log message bits were aligned in a
manner roughly similar to the following:

   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.

Also:

* CHANGES
  Note this change.

(And yes, I'm running out of interesting ways to compose log messages
for merged changes.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2429 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-23 20:29:53 +00:00
cmpilato
3699e8e0c7 Merge from trunk r2426, whose log message read like so:
* 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/branches/1.1.x@2427 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-19 04:19:55 +00:00
cmpilato
55c0b30bc0 Merge from trunk r2424, whose log message read like so:
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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2425 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-13 17:50:42 +00:00
cmpilato
6fd321529a Merge from trunk r2421, whose log message read thusly:
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().

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2422 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-13 16:20:11 +00:00
cmpilato
531877db4a Merge from trunk r2414, whose log message read thusly:
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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2415 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 20:56:50 +00:00
cmpilato
51df003d8e Merge from trunk r2411, whose log message leans a little this way:
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.

Also:

* CHANGES
  Note the fix made in this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2412 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 20:24:45 +00:00
cmpilato
7d05859d7e Merge from trunk r2407 and r2408, which are mostly just some formatting
changes for standalone.py.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2410 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 19:11:30 +00:00
cmpilato
2e48cd2ba1 Merge from trunk r2403, whose log message read like so:
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>

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2404 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-17 20:09:06 +00:00
cmpilato
267b61f347 Merge from trunk r2401, whose log message read thusly:
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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2402 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-15 15:20:50 +00:00
cmpilato
7f53d5cc3c Merge from trunk r2399, whose log message read like so:
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/branches/1.1.x@2400 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-03 19:43:43 +00:00
cmpilato
af591ed9f7 Minor process and verbiage tweak. (Merge from trunk r2393.)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2394 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 14:38:23 +00:00
cmpilato
17492a3856 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2389 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 13:59:23 +00:00
cmpilato
e990ff9f2f And we might as well release 1.1.6 today, too.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2387 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 13:24:27 +00:00
cmpilato
d832930c8d Shorten the update/copy instructions. (Merge r2381 from /trunk.)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2382 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 12:51:07 +00:00
cmpilato
8a0c66c7cf Merge from trunk r2379, whose log message read like so:
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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2380 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 19:43:32 +00:00
cmpilato
292c2d7ce0 Merge from trunk r2376-r2377, whose log messages read like so:
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.

   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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2378 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 19:12:26 +00:00
cmpilato
16937af30f Merge from trunk r2374, whose log message read like so:
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>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2375 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 15:08:46 +00:00
cmpilato
d067d49afa Merge from trunk r2372, some rcsparse optimizations.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2373 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 14:58:14 +00:00
cmpilato
132a01a88f Merge from trunk r2369, whose log message read like so:
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>

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2370 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-06 13:53:46 +00:00
cmpilato
4db5103ff1 Merge from trunk r2367, some INSTALL notes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2368 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-05 15:26:44 +00:00
cmpilato
41943f67c5 Merge from trunk r2271, whose log message read thusly:
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>

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2366 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-04 17:23:06 +00:00
cmpilato
1f37623526 Lose bogus MIME type in favicon link tag. (Merge r2364 from trunk.)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2365 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-04-21 19:08:14 +00:00
cmpilato
7e92babad8 Merge from trunk r2362, whose log message read like so:
* 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/branches/1.1.x@2363 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-04-14 17:19:28 +00:00
cmpilato
97e45101d9 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2356 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:51:14 +00:00
cmpilato
62d5a3b649 Bump copyright year in LICENSE.html.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2353 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:37:39 +00:00
cmpilato
c96c585b39 Copyright bumps only.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2350 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:32:43 +00:00
cmpilato
136063e5a7 Update CHANGES file for today's release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2347 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:24:33 +00:00
cmpilato
f59db1597d Merge from trunk r2344, whose log message read like so:
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().

NOTE: the WsgiServer.escape() change didn't apply to this branch.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2345 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-11 20:01:08 +00:00
cmpilato
c6c3f55c2c Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2334 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:28:51 +00:00
cmpilato
8063d46a53 Schedule the release of 1.1.4.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2332 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:22:31 +00:00
cmpilato
fbc7737465 Merge some copyright year bumps.
(Also, an inadvertant commit of a CHANGES typo fix.)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2331 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:18:17 +00:00
cmpilato
23f3f3ad55 Merge from trunk r2325 and r2326:
* lib/viewvc.py
     (query_backup): Switch to using the sapi interface for output file
       I/O instead of using 'print'.
     (view_queryform): Escape user-provided input before passing it
       directly off to the templates.  Can you say "CSS attack vector"?

Also:

* CHANGES
  Note the security fix.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2327 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-02-10 19:23:06 +00:00
cmpilato
0efc53a373 Merge from trunk r2322 (a docs fix).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2323 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-01-29 14:31:53 +00:00
cmpilato
0cfe027753 Merge from trunk r2320, whose log message read like so:
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>

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2321 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-01-19 15:12:51 +00:00
cmpilato
df3b75cdb0 Merge from trunk r2318, whose log message read like so:
* 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/branches/1.1.x@2319 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-01-08 17:47:29 +00:00
cmpilato
24dd18bf0f Merge from trunk r2316, whose log message read like so:
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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2317 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-01-07 16:08:31 +00:00
cmpilato
bbf27f4afd Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2312 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-22 20:49:36 +00:00
cmpilato
d4ac97de3c Commit to a release date of today for 1.1.3. Merry Christmas.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2310 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-22 19:52:47 +00:00
cmpilato
3039b1f43b Merge from trunk r2308, whose log message was somethin' like this:
* 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/branches/1.1.x@2309 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-08 17:13:53 +00:00
cmpilato
13597f89cd Merge from trunk r2306, whoc log message read as such:
* conf/viewvc.conf.dist
     Try to consistify the way our admonishments appear herein.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2307 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-08 17:06:42 +00:00
cmpilato
870ae9aecc Merge r2303 from trunk (or, the deletion half of the viewvc.org directory
move, at least).

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2304 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-04 21:52:11 +00:00
cmpilato
c94b0709ec Merge from trunk r2300, whose log message read thusly:
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.

Also:

* CHANGES
  Note these changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2301 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-03 06:09:25 +00:00
cmpilato
5632e63bcb * CHANGES
Minor typo fix.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2299 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-03 05:59:37 +00:00
cmpilato
ae7b1103f6 Merge from trunk r2297, whose log message read thusly:
* lib/query.py
     (run_query): Expand roots so we're playing with a full deck.

Also:

* CHANGES
  Record this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2298 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-03 05:59:15 +00:00
cmpilato
2882178be7 Merge from trunk r2291 and r2292, which can be summarized like so:
* conf/viewvc.conf.dist,
   * lib/config.py
     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).

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2296 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-02 20:35:21 +00:00
cmpilato
bfc59256ca Merge from trunk r2293, whose log message read like so:
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>

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2294 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-02 16:04:27 +00:00
cmpilato
3abe695c3c Merge from trunk r2288, whose log message read like so:
* 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/branches/1.1.x@2289 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-01 15:01:34 +00:00
cmpilato
624dfdf0f8 Merge from trunk r2286, whose log message read thusly:
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().

Also:

* CHANGES
  Add "#440" to the list of bugs related to this one problem.  Sheesh.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2287 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-01 14:56:21 +00:00
cmpilato
28bf22f279 Merge from trunk r2281, whose log message read like so:
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/branches/1.1.x@2282 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-11-10 22:18:41 +00:00
cmpilato
830a48f88c Merge from trunk r2279, whose log message read like so:
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>

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2280 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-11-05 16:36:29 +00:00
cmpilato
a23543d763 Merge from trunk r2277, whose log message read like so:
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>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2278 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-25 22:19:24 +00:00
cmpilato
586a183d5c Merge from trunk r2275, whose log message read:
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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2276 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-25 20:57:16 +00:00
cmpilato
7ae02a5887 Merge from trunk r2273, whose log message read like so:
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/branches/1.1.x@2274 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-08 17:54:08 +00:00
cmpilato
4020fd2e5f Merge from trunk r2269 and r2270, which contain some INSTALL file
reformatting/clarification tweaks.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2272 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-08 17:46:57 +00:00
cmpilato
af871d59ce Tweak change to note additional issues.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2267 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 19:10:50 +00:00
cmpilato
b8d36c8c14 Merge from trunk r2265 whose log message read:
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>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2266 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 18:58:34 +00:00
cmpilato
4b5721a3d7 Merge from trunk r2263 (a typo fix in a comment).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2264 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 16:03:50 +00:00
cmpilato
10235b8fdf Merge from trunk r2261, whose log message read like so:
* 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/branches/1.1.x@2262 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 15:58:54 +00:00
cmpilato
45332f577a Merge from trunk r2259, whose log message read:
* templates/file.ezt
     Don't point folks to the checkout view if it's disabled.

Also:

* CHANGES
  Note (generically) this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2260 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 14:34:55 +00:00
cmpilato
148fd7b462 Merge from trunk r2257, whose log message read like so:
* 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/branches/1.1.x@2258 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-31 15:04:01 +00:00
cmpilato
6f66313b51 Merge from trunk r2255, which has some HtmlFormatter improvements.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2256 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-27 15:18:20 +00:00
cmpilato
cf32af4816 Merge from trunk r2252, whose log read:
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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2254 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-25 15:30:31 +00:00
cmpilato
df3addacdb Merge from trunk r2251, whose log message read:
* 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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2253 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-25 15:28:12 +00:00
cmpilato
a1428600b7 Merge from trunk r2249, whose log message read thusly:
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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2250 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-24 15:11:05 +00:00
cmpilato
4a4a3b1d61 Merge from trunk r2247, whose log message read:
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/branches/1.1.x@2248 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-21 15:59:02 +00:00
cmpilato
8c65f1b2c5 Merge from trunk r2244 and r2245, which fixes issue #3 (where truncation of
log messages for display purposes caused marked-up URLs to also be truncated),
and which paves the way for custom bug/issue ID linkification.

* lib/viewvc.py
  See r2244 and r2245.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2246 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-21 15:11:56 +00:00
cmpilato
55046f2261 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2236 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 13:09:49 +00:00
cmpilato
b6cedd7c1a Merge 1.0.9 changes, and prep for 1.1.2 release today.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2234 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 13:03:51 +00:00
cmpilato
771d6736fb Merge from trunk r2228, whose log message read thusly:
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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2229 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-16 19:30:25 +00:00
cmpilato
455157e413 Merge from trunk r2225, whose log message read:
* 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/branches/1.1.x@2226 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-14 20:45:03 +00:00
cmpilato
c875582cfe Merge from trunk r2223, whose log message read as follows:
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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2224 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-13 17:15:58 +00:00
cmpilato
c3d896d5a8 Merge from trunk r2220, whose log message read as follows:
* 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/branches/1.1.x@2221 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-07 14:06:18 +00:00
cmpilato
236069b068 Merge from trunk r2217, whose log message read thusly:
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.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2218 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 19:05:08 +00:00
cmpilato
6de96c4fc6 Merge from trunk r2211, r2212, and r2213, whose combined log message
might have read as follows:

   * 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): Use an intermediate variable to simplify some
       logic around input parameter validation.  Move the logic that maps
       view=rev to view=revision into the parameter validation loop.
       Lose now-unnecessary validation of 'content-type' parameter -- the
       normal parameter validation stuff should catch problems there.

Also:

* CHANGES
  Record the relevant bits of these changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2215 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 16:45:59 +00:00
cmpilato
e45c2fcf6e Merge a minor comment tweak from trunk r2209.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2210 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-17 21:22:39 +00:00
cmpilato
8c620c8c1a Merge from trunk r2207, whose log message read thusly:
* 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/branches/1.1.x@2208 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-17 14:33:40 +00:00
cmpilato
c6d6dc4bdf Merge from trunk r2205, whose log message read thusly:
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/branches/1.1.x@2206 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-16 15:05:56 +00:00
cmpilato
355fac5da1 Merge from trunk r2201, which contains some minor documentation
markup tweaks.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2202 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-15 20:12:15 +00:00
cmpilato
77d0c3dd06 Merge from trunk r2199, whose log message read thusly:
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/branches/1.1.x@2200 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-15 19:42:48 +00:00
cmpilato
d95cb540f5 Merge from trunk a minor doc tweak made in r2197.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2198 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-15 19:07:24 +00:00
cmpilato
98b757de23 Merge from trunk r2194 and r2195, whose combined log messages might
read like so:

   Finish issue #420 - "cvsdbadmin rebuild" and "svndbadmin rebuild"
   complain about unknown repositories.
   
   * 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.
   
   * 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.

Also:

* CHANGES
  Record this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2196 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-08 15:53:47 +00:00
cmpilato
efb811d20c Merge from trunk r2192, whose log message read:
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.

Additionally:

* CHANGES
  Record this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2193 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-05 19:05:00 +00:00
cmpilato
a57e6b7054 Merge from trunk r2190, whose log message read:
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/branches/1.1.x@2191 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-05 17:54:34 +00:00
cmpilato
fe52bbb079 [Merge from trunk r2095]
Fix issue #400: Allow ViewVC to (optionally) use the 'chardet' module
during syntax coloration to perform character encoding detection (and
subsequent translation to UTF-8).
   
* conf/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/branches/1.1.x@2188 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-04 15:41:53 +00:00
cmpilato
76d6b541c3 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2187 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-03 15:06:16 +00:00
cmpilato
269a9ca864 Let's get 1.1.1 out today, shall we?
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2184 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-03 14:37:14 +00:00
cmpilato
a5aafe3172 Merge from trunk r2181, whose log message read like so:
* templates/file.ezt
     Use "Contents of /path/to/file" instead of "Annotate of /path/to/file" as
     the page title.

Also:

* CHANGES
  Record this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2182 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-29 17:59:11 +00:00
cmpilato
d30bd89c42 Merge from trunk r2178, whose log message read thusly:
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>

...and r2179, which went like so:

   * lib/cvsdb.py
     (CheckinDatabase.PurgeRepository): Don't allow the purge operation
       to actually *create* a "repositories" table entry.

And while we're at it:

* CHANGES
  Record these changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2180 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-29 15:15:25 +00:00
cmpilato
d76ce85625 Add issue number to recent CHANGES addition.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2177 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-28 14:08:31 +00:00
cmpilato
b2b247f417 Merge from trunk r2175, whose log message read thusly:
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>

Also:

* CHANGES
  Record this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2176 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-28 14:01:21 +00:00
cmpilato
3ab2ec665b And the release cycle begins again...
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2162 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 14:15:53 +00:00
cmpilato
2806f0e9a2 Add date to CHANGES file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2160 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 13:37:54 +00:00
cmpilato
8b426f6fb3 Merge from trunk r2152, recording 1.0.8's CHANGES here.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2153 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:26:56 +00:00
cmpilato
19ee8b32df Record a merge that effectively happened in r2147.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2148 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:09:57 +00:00
cmpilato
a5389019fa Bump copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2147 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:09:01 +00:00
cmpilato
7f272fbe04 Merge from trunk r2123 and r2124, the log message summary of which is:
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.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2144 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:01:10 +00:00
cmpilato
89edf0ac04 Merge from trunk r2142, whose log message read thusly:
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.)

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2143 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 15:49:50 +00:00
cmpilato
71fbec8871 Merge from trunk r2140, whose log message read thusly:
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/branches/1.1.x@2141 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 15:35:06 +00:00
cmpilato
504b1e1a8a Merge from trunk r2137, whose log message read thusly:
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>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2139 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 14:59:32 +00:00
cmpilato
cf9381e0ee Backport to the 1.1.x branch trunk's r2134, whose log message read thusly:
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/branches/1.1.x@2135 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-04 14:58:46 +00:00
cmpilato
3907172131 Merge from trunk r2128-2129.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2130 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-04-20 17:41:32 +00:00
cmpilato
c34752ce92 Merge from trunk r2121, whose log message read thusly:
* 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/branches/1.1.x@2122 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-24 16:34:22 +00:00
cmpilato
40cc23f12a Merge from trunk r2119, whose log message read thusly:
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/branches/1.1.x@2120 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 20:44:47 +00:00
cmpilato
9b7fea99d4 Merge from trunk a few relavent and recent changes (r2110:2117).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2118 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 18:09:29 +00:00
cmpilato
85949a6464 Merge from trunk r2107, which updates copyright info only.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2108 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 16:45:10 +00:00
cmpilato
d5291a6b98 Merge from trunk r2103, whose log message read thusly:
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/branches/1.1.x@2104 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 12:52:24 +00:00
cmpilato
9e41d171c9 Merge from trunk r2101, whose log message read thusly:
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.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2102 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-06 16:44:37 +00:00
cmpilato
da54e91dea Merge from trunk r2097, whose log message read thusly:
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

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2099 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-26 16:15:55 +00:00
cmpilato
41b2ae2c7a Tweak a CHANGES entry for line length reduction.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2098 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-26 16:14:15 +00:00
cmpilato
1815220abe Note r2092 merge CHANGE.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2094 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-20 15:32:57 +00:00
cmpilato
a080d8eef4 Merge from trunk r2090, whose log message read thusly:
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/branches/1.1.x@2092 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-20 15:24:39 +00:00
cmpilato
8c4af42d56 Merge from trunk r2088, whose log message read:
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/branches/1.1.x@2089 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-03 03:54:24 +00:00
cmpilato
7f1d0952fc Backport from trunk r2086, whose log message read thusly:
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/branches/1.1.x@2087 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-02 18:13:11 +00:00
cmpilato
222aa4ec1f Merge from trunk r2083.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2084 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 19:11:15 +00:00
cmpilato
c03bfd4b89 Merge from trunk r2081.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2082 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 18:52:33 +00:00
cmpilato
6fa8cdf117 On the 1.1.x branch: Merge from trunk r2078 and r2079.
* lib/cvsdb.py,
* bin/make-database


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2080 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 18:22:12 +00:00
cmpilato
c4c777ffe6 Backport from trunk r2070.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2071 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-19 19:49:13 +00:00
cmpilato
3680903ed4 Backport from trunk r2067 and r2068.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2069 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-19 19:46:55 +00:00
cmpilato
6fe61a11bb Merge from trunk r2063 and r2064.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2065 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-10 17:28:43 +00:00
cmpilato
437975652f Merge from trunk r2058, whose log message read thusly:
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/branches/1.1.x@2062 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-05 17:25:10 +00:00
cmpilato
7ff75bec7b Record recent merges to this branch.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2060 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-05 17:08:12 +00:00
cmpilato
ea03f20f46 Remove unnecessary empty mergeinfo.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2059 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-05 17:05:29 +00:00
cmpilato
a5df515d79 Merge from trunk r2047, whose log message read thusly:
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.

Why?  Just trying to avoid unnecessary branch divergence.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2057 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-20 16:39:43 +00:00
cmpilato
fabe8e8a66 Merge from trunk r2055, whose log message read thusly:
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/branches/1.1.x@2056 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:45:08 +00:00
cmpilato
f01fcc4ec4 Merge from trunk r2053, whose log message read thusly:
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/branches/1.1.x@2054 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:22:05 +00:00
cmpilato
05e99f4c7b Merge from trunk r2051, whose log message read thusly:
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/branches/1.1.x@2052 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:16:25 +00:00
cmpilato
d8aff4e58f Merge r2048 from trunk.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2049 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 20:07:15 +00:00
cmpilato
e8d3d6ad89 docs/upgrading-howto.html: Don't claim as removed options not in 1.0.x.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2042 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-05 21:13:19 +00:00
cmpilato
1317088e3c * CHANGES: Combine some changes, and remove a now-bogus one.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2040 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-05 16:30:49 +00:00
cmpilato
fe81ee5969 Branch for 1.1 stabilization.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2033 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-30 17:31:36 +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
107 changed files with 12121 additions and 6460 deletions

150
CHANGES
View File

@@ -1,12 +1,155 @@
Version 1.0.11 (released 29-Mar-2010)
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
* handle file:/// Subversion rootpaths as local roots (issue #446)
* restore markup of URLs in file contents (issue #455)
* optionally display last-committed metadata in roots view (issue #457)
Version 1.1.8 (released 02-Dec-2010)
* fix slowness triggered by allow_compress=1 configuration (issue #467)
* allow use of 'fcrypt' for Windows standalone.py authn support (issue #471)
* yield more useful error on directory markup/annotate request (issue #472)
Version 1.1.7 (released 09-Sep-2010)
* display Subversion revision properties in the revision view (issue #453)
* fix exception in 'standalone.py -r REPOS' when run without a config file
* fix standalone.py server root deployments (--script-alias='')
* add Basic authentication support to standalone.py (Unix only) (issue #49)
* fix obscure "unexpected NULL parent pool" Subversion bindings error
* enable path info / link display in remote Subversion root revision view
* fix vhost name case handling inconsistency (issue #466)
* use svn:mime-type property charset param as encoding hint
* markup Subversion revision references in log messages (issue #313)
* add rudimentary support for FastCGI-based deployments (issue #464)
* fix query script WSGI deployment
* add configuration to fix query script cross-linking to ViewVC
Version 1.1.6 (released 02-Jun-2010)
* add rudimentary support for WSGI-based deployments (issue #397)
* fix exception caused by trying to HTML-escape non-string data (issue #454)
* fix incorrect RSS feed Content-Type header (issue #449)
* fix RSS <title> encoding problem (issue #451)
* allow 'svndbadmin purge' to work on missing repositories (issue #452)
Version 1.1.5 (released 29-Mar-2010)
* security fix: escape user-provided search_re input to avoid XSS attack
Version 1.0.10 (released 10-Mar-2010)
Version 1.1.4 (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 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.9 (released 11-Aug-2009)
@@ -223,7 +366,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

257
INSTALL
View File

@@ -19,7 +19,7 @@ Congratulations on getting this far. :-)
For CVS Support:
* Python 1.5.2 or later
* Python 1.5.2 or later (sorry, no 3.x support yet)
(http://www.python.org/)
* RCS, Revision Control System
(http://www.cs.purdue.edu/homes/trinkle/RCS/)
@@ -30,11 +30,11 @@ Congratulations on getting this far. :-)
For Subversion Support:
* Python 2.0 or later
* Python 2.0 or later (sorry, no 3.x support yet)
(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:
@@ -43,11 +43,8 @@ Congratulations on getting this far. :-)
* 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/)
@@ -58,7 +55,7 @@ Congratulations on getting this far. :-)
$ bin/standalone.py -r /PATH/TO/REPOSITORY
This will start a tiny ViewVC server at http://localhost:7467/viewvc/,
This will start a tiny ViewVC server at http://localhost:49152/viewvc/,
to which you can connect with your browser.
Standard operation:
@@ -94,15 +91,9 @@ Visitors viewing those versioned controlled documents get the
malicious code, too, which might not be what the original author
intended.
If you wish to disable ViewVC's "checkout" view which implements this
feature, you can do so by editing lib/viewvc.py, and modifying the
function view_checkout() like so, adding the lines indicated:
def view_checkout(request):
>> raise debug.ViewVCException('Checkout view is disabled',
>> '403 Forbidden')
path, rev = _orig_path(request)
fp, revision = request.repos.openfile(path, rev)
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
@@ -147,8 +138,8 @@ installation instructions.
root_parents (for CVS or Subversion)
default_root
root_as_url_component
rcs_path
mime_types_file
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,
@@ -177,72 +168,145 @@ checkin database working are below.
APACHE CONFIGURATION
--------------------
1) Find out where the web server configuration file is kept. 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.
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>/bin/cgi/viewvc.cgi
ScriptAlias /viewvc <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/viewvc.cgi
into your httpd.conf file. Choose the location in httpd.conf where
also the other ScriptAlias lines reside. Some examples:
ScriptAlias /viewvc /usr/local/viewvc-1.0/bin/cgi/viewvc.cgi
ScriptAlias /query /usr/local/viewvc-1.0/bin/cgi/query.cgi
ScriptAlias /viewvc /usr/local/viewvc-1.0/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
----------------------------------------
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
------------------------------------------
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
------------------------------------------
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.
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/mod_python/
to the directory of your choosing. Modify httpd.conf with the
following directives:
3) Restart apache. The commands to do this vary. "httpd -k restart" and
"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"
WSGIScriptAlias /viewvc <VIEWVC_INSTALLATION_DIRECTORY>/bin/wsgi/viewvc.wsgi
WSGIScriptAlias /query <VIEWVC_INSTALLATION_DIRECTORY>/bin/wsgi/query.wsgi
4) Optional: Add access control.
You'll probably also need the following directive because of the
not-quite-sanctioned way that ViewVC manipulates Python objects.
In your httpd.conf you can control access to certain modules by adding
directives like this:
WSGIApplicationGroup %{GLOBAL}
Note: WSGI support in ViewVC is at this time quite rudimentary,
bordering on downright experimental. Your mileage may vary.
-----------------------------------------
METHOD F: Using mod_fcgid (if installed)
-----------------------------------------
This uses ViewVC's WSGI support (from above), but supports using FastCGI,
and is a somewhat hybrid approach of several of the above methods.
Especially if fcgi is already being used for other purposes, e.g. PHP,
also using fcgi can prevent the need for including additional modules
(e.g. mod_python or mod_wsgi) within Apache, which may help lessen Apache's
memory usage and/or help improve performance.
This depends on mod_fcgid:
http://httpd.apache.org/mod_fcgid/
as well as the fcgi server from Python's flup package:
http://pypi.python.org/pypi/flup
http://trac.saddi.com/flup
The following are some example httpd.conf fragments you can use to
support this configuration:
ScriptAlias /viewvc /usr/local/viewvc/bin/wsgi/viewvc.fcgi
ScriptAlias /query /usr/local/viewvc/bin/wsgi/query.fcgi
4) [Optional] Add access control.
In your httpd.conf you can control access to certain modules by
adding directives like this:
<Location "<url to viewvc.cgi>/<modname_you_wish_to_access_ctl>">
AllowOverride None
@@ -260,7 +324,14 @@ or if you've got Mod_Python installed you can use METHOD D:
http://<server_name>/viewvc/~checkout~/<module_name>
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
5) Optional: Protect your ViewVC instance from server-whacking webcrawlers.
5) Restart Apache.
The commands to do this vary. "httpd -k restart" and "apache -k
restart" are two common variants. On RedHat Linux it is done using
the command "/sbin/service httpd restart" and on SuSE Linux it is
done with "rcapache restart". Other systems use "apachectl restart".
6) Optional: Protect your ViewVC instance from server-whacking webcrawlers.
As ViewVC is a web-based application which each page containing various
links to other pages and views, you can expect your server's performance
@@ -361,27 +432,37 @@ there are some additional steps required to get the database working.
ALL <VIEWVC_INSTALLATION_DIRECTORY>/bin/loginfo-handler %{sVv} cvsnt
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 rebuild "$REPOS" "$REV"
#!/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 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.
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.
You should be ready to go. Click one of the "Query revision history"
links in ViewVC directory listings and give it a try.
@@ -390,20 +471,11 @@ links in ViewVC directory listings and give it a try.
ENABLING SYNTAX COLORATION
--------------------------
Enscript and Highlight are two programs that can colorize source code
for a lot of languages. ViewVC can be configured to use either one.
1) Install Enscript or Highlight using your system's package manager
or downloading from the project home pages.
2) Set either the 'use_enscript' or 'use_highlight' options in
viewvc.conf to 1.
3) You may also need to set 'enscript_path' or 'highlight_path' option
if the executables are not located on the system PATH.
That's it! Now when you view the contents of recognized filetypes in
ViewVC, you should see colorized syntax.
ViewVC uses Pygments (http://pygments.org) for syntax coloration. You
need only install a suitable version of that module, and if ViewVC
finds it in your Python module path, it will use it (unless you
specifically disable the feature by setting use_pygments = 0 in your
viewvc.conf file).
CVSGRAPH CONFIGURATION
@@ -441,9 +513,12 @@ SUBVERSION INTEGRATION
Unlike the CVS integration, which simply wraps the RCS and CVS utility
programs, the Subversion integration requires additional Python
libraries. To use ViewVC with Subversion, make sure you have both
Subversion itself and the Subversion Python bindings installed. See
Subversion's installation notes for more details on how to build and
install these items.
Subversion itself and the Subversion Python bindings installed. These
can be obtained through typical package distribution mechanisms, or
may be build from source. (See the files 'INSTALL' and
'subversion/bindings/swig/INSTALL' in the Subversion source tree for
more details on how to build and install Subversion and its Python
bindings.)
Generally speaking, you'll know when your installation of Subversion's
bindings has been successful if you can import the 'svn.core' module
@@ -457,7 +532,7 @@ Python binding you have:
Type "help", "copyright", "credits" or "license" for more information.
>>> from svn.core import *
>>> "%s.%s.%s" % (SVN_VER_MAJOR, SVN_VER_MINOR, SVN_VER_PATCH)
'1.2.0'
'1.3.1'
>>>
Note that by default, Subversion installs its bindings in a location
@@ -465,7 +540,7 @@ that is not in Python's default module search path (for example, on
Linux systems the default is usually /usr/local/lib/svn-python). You
need to remedy this, either by adding this path to Python's module
search path, or by relocating the bindings to some place in that
search path.
search path.
For example, you might want to create .pth file in your Python
installation directory's site-packages area which tells Python where
@@ -501,7 +576,7 @@ error: you can't see any files)
CVS-Repository. The CGI-script generally runs as the same user
that the web server does, often user 'nobody' or 'httpd'.
* 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:

View File

@@ -15,7 +15,7 @@
<blockquote>
<p><strong>Copyright &copy; 1999-2010 The ViewCVS Group. All rights
<p><strong>Copyright &copy; 1999-2011 The ViewCVS Group. All rights
reserved.</strong></p>
<p>By using ViewVC, you agree to the terms and conditions set forth
@@ -59,7 +59,9 @@
<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>
</ul>
</body>

53
TODO
View File

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

View File

@@ -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

@@ -54,4 +54,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-2008 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -43,10 +43,10 @@ import os
import string
import cvsdb
import viewvc
import vclib.bincvs
import vclib.ccvs
def UpdateFile(db, repository, path, update):
def UpdateFile(db, repository, path, update, quiet_level):
try:
if update:
commit_list = cvsdb.GetUnrecordedCommitList(repository, path, db)
@@ -57,20 +57,27 @@ def UpdateFile(db, repository, path, update):
return
file = string.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:
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, quiet_level):
for entry in repository.listdir(directory, None, {}):
path = directory + [entry.name]
@@ -78,13 +85,13 @@ def RecurseUpdate(db, repository, directory, update):
continue
if entry.kind is vclib.DIR:
RecurseUpdate(db, repository, path, update)
RecurseUpdate(db, repository, path, update, quiet_level)
continue
if entry.kind is vclib.FILE:
UpdateFile(db, repository, path, update)
UpdateFile(db, repository, path, update, quiet_level)
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 +100,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,46 +119,76 @@ 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)
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)
RecurseUpdate(db, repository, path_parts,
command == 'update', quiet_level)
except KeyboardInterrupt:
print
print '** break **'

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -44,7 +44,7 @@ import getopt
import re
import cvsdb
import viewvc
import vclib.bincvs
import vclib.ccvs
DEBUG_FLAG = 0
@@ -223,7 +223,8 @@ def NextFile(s, pos = 0):
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))

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2007 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,21 +18,22 @@
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,
@@ -92,7 +93,7 @@ CREATE TABLE files (
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=MyISAM;
@@ -120,25 +121,213 @@ CREATE TABLE tags (
) 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=MyISAM;
DROP TABLE IF EXISTS commits;
CREATE TABLE commits (
type enum('Change','Add','Remove'),
ci_when datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
whoid mediumint(9) DEFAULT '0' NOT NULL,
repositoryid mediumint(9) DEFAULT '0' NOT NULL,
dirid mediumint(9) DEFAULT '0' NOT NULL,
fileid mediumint(9) DEFAULT '0' NOT NULL,
revision varchar(32) binary DEFAULT '' NOT NULL,
stickytag varchar(255) binary DEFAULT '' NOT NULL,
branchid mediumint(9) DEFAULT '0' NOT NULL,
addedlines int(11) DEFAULT '0' NOT NULL,
removedlines int(11) DEFAULT '0' NOT NULL,
descid mediumint(9),
UNIQUE repositoryid (repositoryid,dirid,fileid,revision),
KEY ci_when (ci_when),
KEY whoid (whoid),
KEY repositoryid_2 (repositoryid),
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid),
KEY descid (descid)
) TYPE=MyISAM;
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)
) 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=MyISAM;
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=MyISAM;
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=MyISAM;
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=MyISAM;
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=MyISAM;
DROP TABLE IF EXISTS metadata;
CREATE TABLE metadata (
name varchar(255) binary DEFAULT '' NOT NULL,
value text,
PRIMARY KEY (name),
UNIQUE name (name)
) TYPE=MyISAM;
INSERT INTO metadata (name, value) VALUES ('version', '1');
"""
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 +335,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,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -65,7 +65,10 @@ cfg = viewvc.load_config(CONF_PATHNAME)
def index(req):
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()

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 2004 James Henstridge
# Copyright (C) 2004-2008 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
@@ -28,8 +28,8 @@
#
# 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.
#
# -----------------------------------------------------------------------
#
@@ -50,9 +50,9 @@ import sys
import os
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], "../../lib")))
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], "../../lib")))
#########################################################################
@@ -67,24 +67,22 @@ import svn.delta
import cvsdb
import viewvc
import vclib
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):
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)
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+))?')
@@ -134,39 +132,36 @@ def _get_diff_counts(diff_fp):
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.RevisionChangeCollector(repo.fs, rev)
e_ptr, e_baton = svn.delta.make_editor(editor)
svn.repos.svn_repos_replay(fsroot, e_ptr, e_baton)
self.changes = []
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
base_root = None
@@ -183,8 +178,7 @@ class SvnRev:
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, [])
change.path and change.path or None)
diff_fp = diffobj.get_pipe()
plus, minus = _get_diff_counts(diff_fp)
self.changes.append((path, action, plus, minus))
@@ -193,12 +187,11 @@ class SvnRev:
"""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
@@ -232,7 +225,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
@@ -245,38 +238,83 @@ 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)
# 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)
# Record what must be recorded.
if command in ('rebuild', 'update'):
if not os.path.exists(repository):
sys.stderr.write('ERROR: could not find repository %s\n'
% (repository))
sys.exit(1)
repo = SvnRepo(repository)
if command == 'rebuild' or (command == 'update' and not revs):
for rev in range(repo.rev_max+1):
handle_revision(db, command, repo, rev, verbose)
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:
for rev in range(repo.rev_max+1):
handle_revision(db, command, repo, rev, verbose)
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')
@@ -284,29 +322,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'):
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)

54
bin/wsgi/query.fcgi Normal file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/python
# -*-python-*-
#
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a fcgi entry point for the query ViewVC app. It's appropriate
# for use with mod_fcgid and flup. It defines a single application function
# that is a valid fcgi entry point.
#
# mod_fcgid: http://httpd.apache.org/mod_fcgid/
# flup:
# http://pypi.python.org/pypi/flup
# http://trac.saddi.com/flup
#
# -----------------------------------------------------------------------
import sys, os
LIBRARY_DIR = None
CONF_PATHNAME = None
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
"../../../lib")))
import sapi
import viewvc
import query
from flup.server import fcgi
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc_base_url = cfg.query.viewvc_base_url
if viewvc_base_url is None:
viewvc_base_url = "viewvc.fcgi"
query.main(server, cfg, viewvc_base_url)
return []
fcgi.WSGIServer(application).run()

45
bin/wsgi/query.wsgi Normal file
View File

@@ -0,0 +1,45 @@
# -*-python-*-
#
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a wsgi entry point for the query ViewVC app. It's appropriate
# for use with mod_wsgi. It defines a single application function that
# is a valid wsgi entry point.
#
# -----------------------------------------------------------------------
import sys, os
LIBRARY_DIR = None
CONF_PATHNAME = None
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
"../../../lib")))
import sapi
import viewvc
import query
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc_base_url = cfg.query.viewvc_base_url
if viewvc_base_url is None:
viewvc_base_url = "viewvc.wsgi"
query.main(server, cfg, viewvc_base_url)
return []

50
bin/wsgi/viewvc.fcgi Normal file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/python
# -*-python-*-
#
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a fcgi entry point for the main ViewVC app. It's appropriate
# for use with mod_fcgid and flup. It defines a single application function
# that is a valid fcgi entry point.
#
# mod_fcgid: http://httpd.apache.org/mod_fcgid/
# flup:
# http://pypi.python.org/pypi/flup
# http://trac.saddi.com/flup
#
# -----------------------------------------------------------------------
import sys, os
LIBRARY_DIR = None
CONF_PATHNAME = None
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
"../../../lib")))
import sapi
import viewvc
from flup.server import fcgi
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc.main(server, cfg)
return []
fcgi.WSGIServer(application).run()

41
bin/wsgi/viewvc.wsgi Normal file
View File

@@ -0,0 +1,41 @@
# -*-python-*-
#
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a wsgi entry point for the main ViewVC app. It's appropriate
# for use with mod_wsgi. It defines a single application function that
# is a valid wsgi entry point.
#
# -----------------------------------------------------------------------
import sys, os
LIBRARY_DIR = None
CONF_PATHNAME = None
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
"../../../lib")))
import sapi
import viewvc
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc.main(server, cfg)
return []

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).
#
#

1127
conf/viewvc.conf.dist Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,11 +2,35 @@
<html>
<head>
<title>ViewVC: Upgrading</title>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
<style>
body {
background-color: rgb(180,193,205);
color: black;
font-family: sans-serif;
}
table { margin-left: 1em; }
td, th { padding: 0 0.5em; }
th {
vertical-align: bottom;
background: rgb(60%,70%,90%);
}
td {
vertical-align: top;
}
.h2, .h3 {
padding: 0.5em 1em;
border-color: black;
border-style: solid;
margin-bottom: 1em;
background: white;
}
.h2 { border-width: 1px 2px 2px 1px; }
.h3 { border-width: 1px 0 0 0; }
.toc-list { font-size: 90%; }
.varname { font-family: monospace; }
.unchanged { background: rgb(50%,75%,50%); }
.renamed { background: rgb(75%,100%,75%); }
.added { background: rgb(50%,75%,25%); }
.unchanged { background: rgb(75%,75%,75%); }
.renamed { background: rgb(75%,50%,75%); }
.changed { background: rgb(100%,100%,25%); }
.replaced { background: rgb(100%,75%,0%); }
.removed { background: rgb(100%,25%,25%); }
@@ -15,45 +39,10 @@
<body>
<div id="title">
<a href="http://www.viewvc.org/"><img
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
</div>
<h1>Upgrading ViewVC</h1>
<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-upgrading">Upgrading Basics</a></li>
<li><a href="#sec-from-0-9">Upgrading from 0.9</a></li>
<li><a href="#sec-from-0-8">Upgrading from 0.8</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-upgrading">Upgrading Basics</h2>
<div class="h2">
<h2 id="introduction">Introduction</h2>
<p>This document describes some of the things that you will need to
consider, change, or handle when upgrading an existing ViewVC
@@ -67,18 +56,632 @@
directory and to carefully compare the configuration files. A
possible approach is to name the directories
<code>/usr/local/viewvc-1.0</code>,
<code>/usr/local/viewcvs-1.1</code> and so on and than create a
<code>/usr/local/viewvc-1.1</code> and so on and than create a
symbolic link <code>viewvc</code> pointing to the production
version. This way you can easily test several versions and switch
back if your users start to complain.</p>
</div>
<div class="section">
<div class="h2">
<h2 id="toc">Table of Contents</h2>
<ul class="toc-list">
<li><a href="#introduction">Introduction</a></li>
<li><a href="#sec-from-1-0">Upgrading From ViewVC 1.0</a></li>
<li><a href="#sec-from-0-9">Upgrading From ViewCVS 0.9</a></li>
<li><a href="#sec-from-0-8">Upgrading From ViewCVS 0.8</a></li>
</ul>
</div>
<div class="h2">
<h2 id="sec-from-1-0">Upgrading From ViewVC 1.0</h2>
<p>This section discusses how to upgrade ViewVC 1.0.x to ViewVC 1.1.x.</p>
<div class="h3">
<h3>root_as_url_component Now Enabled by Default</h3>
<p>In ViewVC 1.1, the <code>root_as_url_component</code> configuration
option is now enabled by default. This option causes ViewVC URLs
to be of the form
<code>&hellip;/root-name/path-in-root[?&hellip;]</code> instead of
<code>&hellip;/path-in-root/?root=root-name[&amp;&hellip;]</code>,
and makes for a much more intuitive user experience,
navigation-wise, when ViewVC is serving up multiple version control
repositories. When in this mode, ViewVC will automatically perform
the obvious redirection for URLs which have a <code>root=</code>
CGI parameter.</p>
<p>Unfortunately, there's a catch. Older URLs for the default root
(specified by the <code>default_root</code> configuration option)
were optimized to <em>not</em> include the <code>root=</code> CGI
parameter. This means they look unfortunately similar to the newer
root-in-the-path URL format, and ViewVC will not attempt to
redirect them. But ViewVC won't be able to handle them, either.
So, old-style default-root URLs, when aimed at a ViewVC for which
the <code>root_as_url_component</code> option has been subsequently
enabled, will result in an error. If you need to preserve the
functionality of those old URLs, you'll need to either disable
<code>root_as_url_component</code>, or use some other mechanism
(like server URL rewriting) to morph them into compliance with the
new URL format.</p>
</div>
<div class="h3">
<h3>Path-Based Authorization / Forbidden Modules</h3>
<p>ViewVC 1.1 introduces a new pluggable authorization (authz)
subsystem which gives administrators greater control over the
accessibility of the information ViewVC displays in its output.
ViewVC provides a number of working authz modules and a framework for
configuring them. But of specific interest to folks upgrading from
ViewVC 1.0 is that one of these new modules has replaced the
handling of forbidden modules. As such, the <code>forbidden</code>
configuration option now lives under the configuration section
specific to that authz module.</p>
<p>Migrating your existing configuration of forbidden modules should
be fairly straightforward:</p>
<ol>
<li>In the new "authz-forbidden" section of viewvc.conf, set the
<code>forbidden</code> option to the same value as the
<code>forbidden</code> option in your ViewVC 1.0.x
configuration's "general" section.</li>
<li>In the new "authz-forbiddenre" section of viewvc.conf, set the
<code>forbiddenre</code> option to the same value as the
<code>forbiddenre</code> option in your ViewVC 1.0.x
configuration's "general" section.</li>
<li>Finally, ensure that that the new <code>authorizer</code>
option is set to either "forbidden" or "forbiddenre", depending
on which of those you were using in ViewVC 1.0.x.</li>
</ol>
<p>Of course, you might wish to take advantage of another of the
provided authz modules. Or, you might wish to write a brand new
one for your purposes. The flexibility is yours.</p>
<p><strong>Known Issues:</strong></p>
<ul>
<li>ViewVC does not provide an <em>authentication</em> framework.
It does, however, inherit authenticated usernames as determined
by the HTTP server (Apache, e.g.) via the CGI environment. So,
any authorization module that assigns privileges based on
usernames will work only if ViewVC is deployed in a way that
requires successful authentication (as opposed to allowing
anonymous access).</li>
<li>Currently, the root listing view only honors the global or
vhost-specific configurations, <em>not</em> any root-specific
configuration. In the event that ViewVC is using root-specific
configuration for its authorization stuffs, this may cause
either the unintended leak of root names to users or the
inability to see roots at all. However, for root-specific
ViewVC views, all configuration &mdash; include root-specific
configuration &mdash; is honored. If you are concerned about
leaking root names in the root listing view, you might consider
disabling that view altogether by removing <code>roots</code>
from the list of views specified in the
<code>allowed_views</code> configuration option.</li>
<li>The experimental module which allows ViewVC to serve up views
of remote Subversion repositories is not yet fully integrated
with the authorization subsystem, and almost certainly will
leak privileged data. Sorry. That's (one reason) why it's
experimental.</li>
</ul>
</div>
<div class="h3">
<h3>Syntax Highlighting</h3>
<p>ViewVC 1.0.x supports syntax highlighting provided by multiple
third-party highlighting engines, including GNU enscript, GNU
source-highlight, highlight, php, and py2html. Unfortunately, each
of those integrations worked differently than the others. Some
supported line numbers, some didn't; some were under active
development and recognized newer languages; some weren't; each had
its own set of CSS stylations that needed to be customized;
etc.</p>
<p>In ViewVC 1.1, we've dropped support for all of those integations
in favor of a single integration with <a
href="http://www.pygments.org/" >Pygments</a>, a
Python-module-based syntax highlighting engine. As such, the
configuration options for the various other engines (both those
that enabled the integration and those that specified the locations
of the third-party tools) have been removed from ViewVC, and have
been replaced by a single new configuration option:
<code>enable_syntax_coloration</code>.</p>
<p>The list of removed options is as follows:</p>
<ul>
<li>options/enscript_path</li>
<li>options/highlight_convert_tabs</li>
<li>options/highlight_path</li>
<li>options/markup_line_numbers</li>
<li>options/php_exe</li>
<li>options/py2html_path</li>
<li>options/use_enscript</li>
<li>options/use_highlight</li>
<li>options/use_pagesize</li>
<li>options/use_php</li>
<li>options/use_py2html</li>
</ul>
</div>
<div class="h3">
<h3>Checkin Database</h3>
<p>ViewVC 1.1 introduces to the <code>cvsdbadmin</code>
and <code>svndbadmin</code> tools a new "purge" operation, which
allows you to remove all the information related to a given root
from your checkins database (without disturbing the information
associated with other roots). Likewise, the "rebuild" command in
those tools now implies a "purge" followed by an update.</p>
<p>As a related change, the <code>svndbadmin</code> program's
"rebuild" subcommand has had its purpose become more defined. It
no longer accepts a revision argument, and therefore can now only
be used to completely rebuild the entirety of the checkin database
information for a Subversion repository (instead of being able to
only update the information related to single Subversion revision).
For per-revision updating, use <code>svndbadmin update</code> and
provide a revision (or revision range). And to get the previous
rebuild-a-revision effect, pass the new <code>--force</code> option
to <code>svndbadmin update</code>.</p>
<p>In other words, where you once did this:</p>
<blockquote><pre>$ svndbadmin rebuild /path/to/repository 1234
</pre>
</blockquote>
<p>you now need to do this:</p>
<blockquote><pre>$ svndbadmin update /path/to/repository 1234 --force
</pre>
</blockquote>
<p>To enhance the performance of the new "purge" operation, ViewVC 1.1
introduces some slight changes to the checkin database schema. If
you use the <code>make-database</code> tool to (re)create your
checkins database, it will by default employ the new database
schema. This should cause the database to be virtually unusable by
previous versions of ViewVC, and that's by design. If, however,
you need to (re)create your checkins database and you require
compatibility with previous versions of ViewVC or ViewCVS, simply
pass the "--version=1.0" option to the <code>make-database</code>
script. Note that your "purge" and "rebuild" operations could be
abysmally slow, though, as that version of the database schema is
not optimized for those operations.</p>
</div>
<div class="h3">
<h3>Configuration Options</h3>
<p>This section covers changes to configuration options not already
discussed in other sections pertaining to this upgrade.</p>
<p>In ViewVC 1.1, a new "utilities" section was added to the
viewvc.conf file. All the options used for configuring the
locations of various helper applications that ViewVC uses which
were previously scattered throughout the configuration file are now
all centralized in this one new section. To accomplish this, the
following options were added:</p>
<ul>
<li>utilities/cvsgraph</li>
<li>utilities/cvsnt</li>
<li>utilities/diff</li>
<li>utilities/rcs_dir</li>
<li>utilities/svn</li>
</ul>
<p>&hellip;and these were removed:</p>
<ul>
<li>general/cvsnt_ext_path</li>
<li>general/rcs_path</li>
<li>general/svn_path</li>
<li>options/cvsgraph_path</li>
</ul>
<p>All the options which governed which ViewVC views were enabled have
been consolidated into a single new option. This new option:</p>
<ul>
<li>options/allowed_views</li>
</ul>
<p>&hellip;replaces these, which have been removed:</p>
<ul>
<li>options/allow_annotate</li>
<li>options/allow_markup</li>
<li>options/allow_tar</li>
</ul>
<p>ViewVC now honors the "svn:mime-type" property stored on
Subversion-versioned files as the primary source of MIME type
determination (before falling back to name-based MIME mappings and
such). However, this can negatively affect the viewability of
certain files &mdash; especially images &mdash; whose
"svn:mime-type" properties are set incorrectly, such as will happen
if Subversion itself merely determines that the file isn't
human-readable and uses the "application/octet-stream" MIME type to
record this determination. To make ViewVC <em>not</em> honor the
"svn:mime-type" property value, set the <code>svn_ignore_mimetype</code>
configuration option.</p>
<p>Speaking of MIME types, the option <code>mime_types_file</code> is
now <code>mime_types_files</code>, as it now carries multiple paths
to MIME mappings files, ordered by preference.</p>
<p>The <code>use_rcsparse</code> option was moved from the "general"
section to the "options" section.</p>
<p>The <code>log_sort</code> option's value "cvs" has been renamed to
"none" (for general application across all supported version
control systems).</p>
<p>Custom sections which define per-virtual-host configuration option
overrides must now have their names prefixed with "vhost-". Also,
instead of a hyphen (-) between the virtual host name and the base
configuration section being overridden, now there should be a
forward slash character (/). For example, the following
configuration which was valid in ViewVC 1.0 is no longer valid:</p>
<blockquote><pre>[vhosts]
all = viewvc.*
[all-options]
allowed_views = annotate, diff, markup, tar
</pre>
</blockquote>
<p>This now needs to be written like so:</p>
<blockquote><pre>[vhosts]
all = viewvc.*
[vhost-all/options]
allowed_views = annotate, diff, markup, tar
</pre>
</blockquote>
<p>The following is a grab-bag of additional new options:</p>
<ul>
<li>options/hide_errorful_entries</li>
<li>options/mangle_email_addresses</li>
</ul>
</div>
<div class="h3">
<h3>Templates</h3>
<p>This section describes template variable changes introduced in this
release. See the <a href="./template-authoring-guide.html">Template
Authoring Guide</a> for the current set of variables available to
each templates.</p>
<p>One notable change in ViewVC 1.1 is that the markup.ezt and
annotate.ezt templates have been combined into a single file.ezt
template.</p>
<p>Also, the configuration options under the <code>[templates]</code>
section are now paths relative to the configured template directory
(either the value of the <code>options/template_dir</code>
option, or the default "templates" directory), instead of being
relative to the configuration location.</p>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Location</th>
<th>Changes</th>
</tr>
</thead>
<tbody>
<tr class="added">
<td class="varname">rootpath</td>
<td><em>all templates</em></td>
<td>added</td>
</tr>
<tr class="removed">
<td class="varname">change_root_action</td>
<td><em>all templates</em></td>
<td>removed</td>
</tr>
<tr class="removed">
<td class="varname">change_root_hidden_values</td>
<td><em>all templates</em></td>
<td>removed</td>
</tr>
<tr class="removed">
<td class="varname">roots</td>
<td><em>all templates</em> except roots.ezt</td>
<td>removed</td>
</tr>
<tr class="added">
<td class="varname">roots.path</td>
<td>roots.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">queryform_href</td>
<td>diff.ezt, file.ezt, graph.ezt, log.ezt, log_table.ezt,
query_form.ezt, revision.ezt, roots.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">tarball_href</td>
<td>diff.ezt, file.ezt, graph.ezt, log.ezt, log_table.ezt,
query_form.ezt, query_results.ezt, revision.ezt, roots.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">properties</td>
<td>directory.ezt, file.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">properties.name</td>
<td>directory.ezt, file.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">properties.undisplayable</td>
<td>directory.ezt, file.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">properties.value</td>
<td>directory.ezt, file.ezt</td>
<td>added</td>
</tr>
<tr class="changed">
<td class="varname">diff_format_hidden_values</td>
<td>diff.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="changed">
<td class="varname">diff_type</td>
<td>diff.ezt</td>
<td>new value: <code>f</code></td>
</tr>
<tr class="renamed">
<td class="varname">date_left</td>
<td>diff.ezt</td>
<td>renamed to <code>left.date</code></td>
</tr>
<tr class="renamed">
<td class="varname">path_left</td>
<td>diff.ezt</td>
<td>renamed to <code>left.path</code></td>
</tr>
<tr class="renamed">
<td class="varname">rev_left</td>
<td>diff.ezt</td>
<td>renamed to <code>left.rev</code></td>
</tr>
<tr class="renamed">
<td class="varname">tag_left</td>
<td>diff.ezt</td>
<td>renamed to <code>left.tag</code></td>
</tr>
<tr class="renamed">
<td class="varname">date_right</td>
<td>diff.ezt</td>
<td>renamed to <code>right.date</code></td>
</tr>
<tr class="renamed">
<td class="varname">path_right</td>
<td>diff.ezt</td>
<td>renamed to <code>right.path</code></td>
</tr>
<tr class="renamed">
<td class="varname">rev_right</td>
<td>diff.ezt</td>
<td>renamed to <code>right.rev</code></td>
</tr>
<tr class="renamed">
<td class="varname">tag_right</td>
<td>diff.ezt</td>
<td>renamed to <code>right.tag</code></td>
</tr>
<tr class="removed">
<td class="varname">annotate_href</td>
<td>diff.ezt</td>
<td>removed, use <code>right.annotate_href</code> instead</td>
</tr>
<tr class="added">
<td class="varname">left.annotate_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">left.download_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">left.download_text_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">left.prefer_markup</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">left.revision_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">left.view_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">right.annotate_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">right.download_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">right.download_text_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">right.prefer_markup</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">right.revision_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">right.view_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">right.view_href</td>
<td>diff.ezt</td>
<td>added</td>
</tr>
<tr class="changed">
<td class="varname">dir_paging_hidden_values</td>
<td>directory.ezt, , dir_alternate.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="changed">
<td class="varname">entries.log</td>
<td>directory.ezt, dir_alternate.ezt</td>
<td>now always contains untruncated log message</td>
</tr>
<tr class="added">
<td class="varname">entries.short_log</td>
<td>directory.ezt, dir_alternate.ezt</td>
<td>added</td>
</tr>
<tr class="changed">
<td class="varname">search_re_hidden_values</td>
<td>directory.ezt, dir_alternate.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="changed">
<td class="varname">search_tag_hidden_values</td>
<td>directory.ezt, dir_alternate.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="changed">
<td class="varname">pathrev_clear_hidden_values</td>
<td>log.ezt, log_table.ezt, directory.ezt, dir_alternate.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="changed">
<td class="varname">pathrev_hidden_values</td>
<td>log.ezt, log_table.ezt, directory.ezt, dir_alternate.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="renamed">
<td class="varname">annotate_href</td>
<td>log.ezt, log_table.ezt</td>
<td>renamed to <code>head_annotate_href</code></td>
</tr>
<tr class="changed">
<td class="varname">diff_form_hidden_values</td>
<td>log.ezt, log_table.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="renamed">
<td class="varname">download_href</td>
<td>log.ezt, log_table.ezt</td>
<td>renamed to <code>head_download_href</code></td>
</tr>
<tr class="renamed">
<td class="varname">download_text_href</td>
<td>log.ezt, log_table.ezt</td>
<td>renamed to <code>head_download_text_href</code></td>
</tr>
<tr class="changed">
<td class="varname">log_paging_hidden_values</td>
<td>log.ezt, log_table.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="changed">
<td class="varname">logsort_hidden_values</td>
<td>log.ezt, log_table.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="renamed">
<td class="varname">prefer_markup</td>
<td>log.ezt, log_table.ezt</td>
<td>renamed to <code>head_prefer_markup</code></td>
</tr>
<tr class="renamed">
<td class="varname">view_href</td>
<td>log.ezt, log_table.ezt</td>
<td>renamed to <code>head_view_href</code></td>
</tr>
<tr class="added">
<td class="varname">rss_link_href</td>
<td>query.ezt, rss.ezt</td>
<td>added</td>
</tr>
<tr class="changed">
<td class="varname">query_hidden_values</td>
<td>query_form.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="changed">
<td class="varname">jump_rev_hidden_values</td>
<td>revision.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="added">
<td class="varname">num_changes</td>
<td>revision.ezt</td>
<td>added</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="h2">
<h2 id="sec-from-0-9">Upgrading From ViewCVS 0.9</h2>
<p>This section discusses how to upgrade ViewCVS 0.9 to ViewVC 1.0.</p>
<div class="h3">
<h3>CGI Stubs</h3>
<p>The CGI stub scripts haved been moved from
@@ -89,16 +692,22 @@
changed, so you may need to replace copies of the old scripts you
put in other directories.</p>
</div>
<div class="h3">
<h3>Checkin Database</h3>
<p>ViewVC 1.0 reads and writes commit times in the MySQL database in
UTC time rather than local time. This can cause times displayed on
UTC time rather than local time. This can cause times displayed on
the query page to be a few hours off if an old database is being
used with a new version of ViewVC. The best way to fix this is to
rebuild the database with the new version of cvsdbadmin, but it
is also possible to enable a backwards compatibility mode by
setting <code>utc_time = 0</code> at the top of lib/dbi.py</p>
</div>
<div class="h3">
<h3>"checkout_magic" Option</h3>
<p>In ViewVC 1.0, the <code>checkout_magic</code> option has been
@@ -113,6 +722,9 @@
be re-enabled. The <code>viewcvs.conf</code> file describes these
options in detail.</p>
</div>
<div class="h3">
<h3>Configuration Options</h3>
<p>The following options have been added:</p>
@@ -129,7 +741,8 @@
<li>options/root_as_url_component</li>
<li>options/default_file_view</li>
<li>options/sort_group_dirs</li>
<li>options/use_pagesize</li>
<li>options/dir_pagesize</li>
<li>options/log_pagesize</li>
<li>options/limit_changes</li>
<li>options/use_localtime</li>
<li>options/cross_copies</li>
@@ -157,6 +770,9 @@
<li>templates/footer</li>
</ul>
</div>
<div class="h3">
<h3>Templates</h3>
<p>The templates have changed drastically in this version of ViewVC.
@@ -761,7 +1377,7 @@
<tr class="renamed">
<td class="varname">rows.log</td>
<td>dir_alternate.ezt, directory.ezt</td>
<td>renamed to <code>entries.log</code></td>
<td>renamed to <code>entries.short_log</code></td>
</tr>
<tr class="renamed">
<td class="varname">rows.log_file</td>
@@ -961,7 +1577,10 @@
</tbody>
</table>
<h4>Template Arrangement</h4>
</div>
<div class="h3">
<h3>Template Arrangement</h3>
<p>The default templates have been rearranged a bit in ViewVC 1.0.
Specifically, "header.ezt" and "footer.ezt" have moved into the
@@ -979,29 +1598,26 @@
configuration file.</p>
</div>
<div class="section">
</div>
<div class="h2">
<h2 id="sec-from-0-8">Upgrading From ViewCVS 0.8</h2>
<p>
This section discusses how to upgrade ViewCVS 0.8 to version
0.9 or a later version of the software.
</p>
<p>This section discusses how to upgrade ViewCVS 0.8 to version
0.9 or a later version of the software.</p>
<p>
<strong>NOTE:</strong> these changes will bring you up to the
requirements of version 0.9. You must also follow the directions
for <a href="#from9">upgrading from 0.9</a>.
</p>
<p><strong>NOTE:</strong> these changes will bring you up to the
requirements of version 0.9. You must also follow the directions
for <a href="#sec-from-0-9">upgrading from 0.9</a>.</p>
<h3>Configuration Options</h3>
<p>
More templates were introduced in version 0.8 of the software,
which made many of the configuration options obsolete. This
section covers which options were removed. If you made any
changes to these options, then you will need to make
corresponding changes in the templates.
</p>
<div class="h3">
<h3>Configuration Options</h3>
<p>More templates were introduced in version 0.8 of the software,
which made many of the configuration options obsolete. This section
covers which options were removed. If you made any changes to these
options, then you will need to make corresponding changes in the
templates.</p>
<dl>
<dt>
@@ -1090,12 +1706,14 @@
</dl>
<h3>Template Variables</h3>
<p>
Some template variables that were available in 0.8 have been
removed in 0.9. If you have custom templates that refer to these
variables, then you will need to modify your templates.
</p>
</div>
<div class="h3">
<h3>Template Variables</h3>
<p>Some template variables that were available in 0.8 have been
removed in 0.9. If you have custom templates that refer to these
variables, then you will need to modify your templates.</p>
<dl>
<dt><code>directory.ezt</code>: <var>headers</var></dt>
@@ -1146,9 +1764,7 @@
</dl>
</div>
</div>
</td>
</tr>
</table>
</body>
</html>

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>
@@ -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,7 +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>
</tr>
<tr>
<td><code>revision=<var>REVISION</var></code></td>
@@ -342,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>
@@ -405,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 />
@@ -429,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>
@@ -486,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 />
@@ -632,12 +739,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>
@@ -762,37 +877,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>
@@ -854,7 +982,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>
@@ -869,7 +998,8 @@ th.caption {
<tr>
<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>
@@ -879,7 +1009,19 @@ th.caption {
<tr>
<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>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>
@@ -889,27 +1031,33 @@ th.caption {
<tr>
<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=<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=<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=<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=<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>
@@ -967,7 +1115,8 @@ th.caption {
<tr>
<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>
@@ -982,7 +1131,8 @@ th.caption {
<tr>
<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>
@@ -992,7 +1142,19 @@ th.caption {
<tr>
<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>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>
@@ -1002,37 +1164,40 @@ th.caption {
<tr>
<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=<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=<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=<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=<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>
</tr>
<tr>
<td><code>limit=<var>LIMIT</var></code></td>
<td>optional</td>
<td>maximum number of file-revisions to process during a query. Default is value of <code>row_limit</code> configuration option</td>
<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_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>
@@ -1072,7 +1237,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>
@@ -1084,7 +1249,8 @@ th.caption {
<tr>
<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>
@@ -1125,7 +1291,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>
@@ -1152,7 +1321,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 />
@@ -1176,7 +1349,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>
@@ -1193,46 +1371,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>
<h3 id="compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'; other values ignored</h3>
<p><code>content-type=text/vnd.viewcvs-markup</code> and <code>content-type=text/x-cvsweb-markup</code> parameters are treated like a <code>view=markup</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future. Other values of the <code>content-type</code> parameter, which were used to dictate the MIME type of files displayed in the checkout/download view prior to ViewVC 1.0.6, are ignored.</p>
<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. 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

@@ -26,6 +26,7 @@
#
# -----------------------------------------------------------------------
import sys
import string
import os
import re
@@ -101,71 +102,41 @@ 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', string.rstrip(thisline) or '&nbsp;'))
sys.stdout.write('</table>\n')
def main():

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -125,16 +125,30 @@ except AttributeError:
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
def mkdtemp(suffix="", prefix="tmp", dir=None):
# mktemp() only took a single suffix argument until Python 2.3.
# We'll do the best we can.
oldtmpdir = os.environ.get('TMPDIR')
try:
for i in range(10):
if dir:
os.environ['TMPDIR'] = dir
dir = tempfile.mktemp(suffix)
if prefix:
parent, base = os.path.split(dir)
dir = os.path.join(parent, prefix + base)
try:
os.mkdir(dir, 0700)
return dir
except OSError, e:
if e.errno == errno.EEXIST:
continue # try again
raise
finally:
if oldtmpdir:
os.environ['TMPDIR'] = oldtmpdir
elif os.environ.has_key('TMPDIR'):
del(os.environ['TMPDIR'])
raise IOError, (errno.EEXIST, "No usable temporary directory name found")

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -19,51 +19,153 @@ import os
import string
import ConfigParser
import fnmatch
import re
import vclib
#########################################################################
#
# 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', 'forbiddenre',
'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',
'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.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:
@@ -76,6 +178,7 @@ class Config:
fname = string.replace(fname, '%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):
@@ -92,7 +195,13 @@ 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):
@@ -105,28 +214,58 @@ class Config:
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 = string.split(string.lower(vhost), ':')[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,
@@ -137,6 +276,102 @@ class Config:
return None
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_and_params_hack(self, rootname):
"""Return a 2-tuple containing the name and parameters of the
authorizer configured for use with ROOTNAME.
### FIXME: This whole thing is a hack caused by our not being able
### to non-destructively overlay root options when trying to do
### something like a root listing (which might need to get
### different authorizer bits for each and every root in the list).
### Until we have a good way to do that, we expose this function,
### which assumes that base and per-vhost configuration has been
### absorbed into this object and that per-root options have *not*
### been overlayed. See issue #371."""
# We assume that per-root options have *not* been overlayed.
assert(self.root_options_overlayed == 0)
if not self.conf_path:
return None, {}
# Figure out the authorizer by searching first for a per-root
# override, then falling back to the base/vhost configuration.
authorizer = None
root_options_section = 'root-%s/options' % (rootname)
if self.parser.has_section(root_options_section) \
and self.parser.has_option(root_options_section, 'authorizer'):
authorizer = self.parser.get(root_options_section, 'authorizer')
if not authorizer:
authorizer = self.options.authorizer
# No authorizer? Get outta here.
if not authorizer:
return None, {}
# Dig up the parameters for the authorizer, starting with the
# base/vhost items, then overlaying any root-specific ones we find.
params = {}
authz_section = 'authz-%s' % (authorizer)
if hasattr(self, authz_section):
sub_config = getattr(self, authz_section)
for attr in dir(sub_config):
params[attr] = getattr(sub_config, attr)
root_authz_section = 'root-%s/authz-%s' % (rootname, authorizer)
for section in self.parser.sections():
if section == root_authz_section:
for key, value in self._get_parser_items(self.parser, section):
params[key] = value
return authorizer, params
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)
return params
def set_defaults(self):
"Set some default values in the configuration."
@@ -144,28 +379,71 @@ 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.forbiddenre = []
self.general.kv_files = []
self.general.mime_types_files = ["mimetypes.conf"]
self.general.address = ''
self.general.kv_files = [ ]
self.general.languages = ['en-us']
self.utilities.rcs_dir = ''
if sys.platform == "win32":
self.utilities.cvsnt = 'cvs'
else:
self.utilities.cvsnt = None
self.utilities.svn = ''
self.utilities.diff = ''
self.utilities.cvsgraph = ''
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.default_file_view = "log"
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.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 = 0
self.options.hr_ignore_keyword_subst = 1
self.options.hr_intraline = 0
self.options.allow_compress = 0
self.options.template_dir = "templates"
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 = 1
self.options.use_localtime = 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.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.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.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
@@ -180,110 +458,12 @@ class Config:
self.cvsdb.readonly_passwd = ''
self.cvsdb.row_limit = 1000
self.cvsdb.rss_row_limit = 100
self.cvsdb.check_database_for_root = 0
self.options.root_as_url_component = 0
self.options.default_file_view = "log"
self.options.checkout_magic = 0
self.options.sort_by = 'file'
self.options.sort_group_dirs = 1
self.options.hide_attic = 1
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_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.docroot = None
self.options.show_subdir_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.use_localtime = 0
self.options.http_expiration_time = 600
self.options.generate_etags = 1
def is_forbidden(self, root, path_parts, pathtype):
# If we don't have a root and path to check, get outta here.
if not (root and path_parts):
return 0
# Give precedence to the new 'forbiddenre' stuff first.
if self.general.forbiddenre:
# Join the root and path-parts together into one path-like thing.
root_and_path = string.join([root] + path_parts, "/")
if pathtype == vclib.DIR:
root_and_path = root_and_path + '/'
# If we still have a list of strings, replace those suckers with
# lists of (compiled_regex, negation_flag)
if type(self.general.forbiddenre[0]) == type(""):
for i in range(len(self.general.forbiddenre)):
pat = self.general.forbiddenre[i]
if pat[0] == '!':
self.general.forbiddenre[i] = (re.compile(pat[1:]), 1)
else:
self.general.forbiddenre[i] = (re.compile(pat), 0)
# Do the forbiddenness test.
default = 0
for (pat, negated) in self.general.forbiddenre:
match = pat.search(root_and_path)
if negated:
default = 1
if match:
return 0
elif match:
return 1
return default
# If no 'forbiddenre' is in use, we check 'forbidden', which only
# looks at the top-most directory.
elif self.general.forbidden:
# A root and a single non-directory path component? That's not
# a module.
if len(path_parts) == 1 and pathtype != vclib.DIR:
return 0
# Do the forbiddenness test.
module = path_parts[0]
default = 0
for pat in self.general.forbidden:
if pat[0] == '!':
default = 1
if fnmatch.fnmatchcase(module, pat[1:]):
return 0
elif fnmatch.fnmatchcase(module, pat):
return 1
return default
# No forbiddenness configuration? Just allow it.
else:
return 0
self.query.viewvc_base_url = None
def _startswith(somestr, substr):
return somestr[:len(substr)] == substr
def _parse_roots(config_name, config_value):
roots = { }
@@ -295,8 +475,18 @@ def _parse_roots(config_name, config_value):
roots[name] = path
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

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -17,8 +17,17 @@ import time
import fnmatch
import re
import vclib
import dbi
## Current commits database schema version number.
##
## Version 0 was the original Bonsai-compatible version.
##
## Version 1 added the 'metadata' table (which holds the 'version' key)
## and renamed all the 'repository'-related stuff to be 'root'-
##
CURRENT_SCHEMA_VERSION = 1
## error
error = "cvsdb error"
@@ -29,13 +38,13 @@ error = "cvsdb error"
## complient database interface
class CheckinDatabase:
def __init__(self, host, port, user, passwd, database, row_limit):
def __init__(self, host, port, user, passwd, database):
self._host = host
self._port = port
self._user = user
self._passwd = passwd
self._database = database
self._row_limit = row_limit
self._version = None
## database lookup caches
self._get_cache = {}
@@ -47,6 +56,19 @@ class CheckinDatabase:
self._host, self._port, self._user, self._passwd, self._database)
cursor = self.db.cursor()
cursor.execute("SET AUTOCOMMIT=1")
table_list = self.GetTableList()
if 'metadata' in table_list:
version = self.GetMetadataValue("version")
if version is None:
self._version = 0
else:
self._version = int(version)
else:
self._version = 0
if self._version > CURRENT_SCHEMA_VERSION:
raise DatabaseVersionError("Database version %d is newer than the "
"last version supported by this "
"software." % (self._version))
def sql_get_id(self, table, column, value, auto_set):
sql = "SELECT id FROM %s WHERE %s=%%s" % (table, column)
@@ -146,6 +168,45 @@ class CheckinDatabase:
return list
def GetCommitsTable(self):
return self._version >= 1 and 'commits' or 'checkins'
def GetTableList(self):
sql = "SHOW TABLES"
cursor = self.db.cursor()
cursor.execute(sql)
list = []
while 1:
row = cursor.fetchone()
if row == None:
break
list.append(row[0])
return list
def GetMetadataValue(self, name):
sql = "SELECT value FROM metadata WHERE name=%s"
sql_args = (name)
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
try:
(value,) = cursor.fetchone()
except TypeError:
return None
return value
def SetMetadataValue(self, name, value):
assert(self._version > 0)
sql = "REPLACE INTO metadata (name, value) VALUES (%s, %s)"
sql_args = (name, value)
cursor = self.db.cursor()
try:
cursor.execute(sql, sql_args)
except Exception, e:
raise Exception("Error setting metadata: '%s'\n"
"\tname = %s\n"
"\tvalue = %s\n"
% (str(e), name, value))
def GetBranchID(self, branch, auto_set = 1):
return self.get_id("branches", "branch", branch, auto_set)
@@ -237,7 +298,7 @@ class CheckinDatabase:
self.AddCommit(commit)
def AddCommit(self, commit):
ci_when = dbi.DateTimeFromTicks(commit.GetTime())
ci_when = dbi.DateTimeFromTicks(commit.GetTime() or 0.0)
ci_type = commit.GetTypeString()
who_id = self.GetAuthorID(commit.GetAuthor())
repository_id = self.GetRepositoryID(commit.GetRepository())
@@ -250,7 +311,8 @@ class CheckinDatabase:
minus_count = commit.GetMinusCount() or '0'
description_id = self.GetDescriptionID(commit.GetDescription())
sql = "REPLACE INTO checkins"\
sql = "REPLACE INTO %s" % (self.GetCommitsTable())
sql = sql + \
" (type,ci_when,whoid,repositoryid,dirid,fileid,revision,"\
" stickytag,branchid,addedlines,removedlines,descid)"\
"VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
@@ -259,7 +321,24 @@ class CheckinDatabase:
plus_count, minus_count, description_id)
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
try:
cursor.execute(sql, sql_args)
except Exception, e:
raise Exception("Error adding commit: '%s'\n"
"Values were:\n"
"\ttype = %s\n"
"\tci_when = %s\n"
"\twhoid = %s\n"
"\trepositoryid = %s\n"
"\tdirid = %s\n"
"\tfileid = %s\n"
"\trevision = %s\n"
"\tstickytag = %s\n"
"\tbranchid = %s\n"
"\taddedlines = %s\n"
"\tremovedlines = %s\n"
"\tdescid = %s\n"
% ((str(e), ) + sql_args))
def SQLQueryListString(self, field, query_entry_list):
sqlList = []
@@ -273,9 +352,17 @@ class CheckinDatabase:
match = " LIKE "
elif query_entry.match == "glob":
match = " REGEXP "
# use fnmatch to translate the glob into a regexp
# Use fnmatch to translate the glob into a regular
# expression. Sadly, we have to account for the fact
# that in Python 2.6, fnmatch.translate() started
# sticking '\Z(?ms)' at the end of the regular
# expression instead of just '$', and doesn't prepend
# the '^'.
data = fnmatch.translate(data)
if data[0] != '^': data = '^' + data
if data[0] != '^':
data = '^' + data
if data[-7:] == '\Z(?ms)':
data = data[:-7] + '$'
elif query_entry.match == "regex":
match = " REGEXP "
elif query_entry.match == "notregex":
@@ -285,53 +372,70 @@ class CheckinDatabase:
return "(%s)" % (string.join(sqlList, " OR "))
def CreateSQLQueryString(self, query):
tableList = [("checkins", None)]
def CreateSQLQueryString(self, query, detect_leftover=0):
commits_table = self.GetCommitsTable()
tableList = [(commits_table, None)]
condList = []
if len(query.repository_list):
tableList.append(("repositories",
"(checkins.repositoryid=repositories.id)"))
"(%s.repositoryid=repositories.id)"
% (commits_table)))
temp = self.SQLQueryListString("repositories.repository",
query.repository_list)
condList.append(temp)
if len(query.branch_list):
tableList.append(("branches", "(checkins.branchid=branches.id)"))
tableList.append(("branches",
"(%s.branchid=branches.id)" % (commits_table)))
temp = self.SQLQueryListString("branches.branch",
query.branch_list)
condList.append(temp)
if len(query.directory_list):
tableList.append(("dirs", "(checkins.dirid=dirs.id)"))
tableList.append(("dirs",
"(%s.dirid=dirs.id)" % (commits_table)))
temp = self.SQLQueryListString("dirs.dir", query.directory_list)
condList.append(temp)
if len(query.file_list):
tableList.append(("files", "(checkins.fileid=files.id)"))
tableList.append(("files",
"(%s.fileid=files.id)" % (commits_table)))
temp = self.SQLQueryListString("files.file", query.file_list)
condList.append(temp)
if len(query.author_list):
tableList.append(("people", "(checkins.whoid=people.id)"))
tableList.append(("people",
"(%s.whoid=people.id)" % (commits_table)))
temp = self.SQLQueryListString("people.who", query.author_list)
condList.append(temp)
if len(query.comment_list):
tableList.append(("descs",
"(%s.descid=descs.id)" % (commits_table)))
temp = self.SQLQueryListString("descs.description",
query.comment_list)
condList.append(temp)
if query.from_date:
temp = "(checkins.ci_when>=\"%s\")" % (str(query.from_date))
temp = "(%s.ci_when>=\"%s\")" \
% (commits_table, str(query.from_date))
condList.append(temp)
if query.to_date:
temp = "(checkins.ci_when<=\"%s\")" % (str(query.to_date))
temp = "(%s.ci_when<=\"%s\")" \
% (commits_table, str(query.to_date))
condList.append(temp)
if query.sort == "date":
order_by = "ORDER BY checkins.ci_when DESC,descid"
order_by = "ORDER BY %s.ci_when DESC,descid" % (commits_table)
elif query.sort == "author":
tableList.append(("people", "(checkins.whoid=people.id)"))
tableList.append(("people",
"(%s.whoid=people.id)" % (commits_table)))
order_by = "ORDER BY people.who,descid"
elif query.sort == "file":
tableList.append(("files", "(checkins.fileid=files.id)"))
tableList.append(("files",
"(%s.fileid=files.id)" % (commits_table)))
order_by = "ORDER BY files.file,descid"
## exclude duplicates from the table list, and split out join
@@ -349,28 +453,35 @@ class CheckinDatabase:
conditions = string.join(joinConds + condList, " AND ")
conditions = conditions and "WHERE %s" % conditions
## limit the number of rows requested or we could really slam
## a server with a large database
## apply the query's row limit, if any (so we avoid really
## slamming a server with a large database)
limit = ""
if query.limit:
limit = "LIMIT %s" % (str(query.limit))
elif self._row_limit:
limit = "LIMIT %s" % (str(self._row_limit))
if detect_leftover:
limit = "LIMIT %s" % (str(query.limit + 1))
else:
limit = "LIMIT %s" % (str(query.limit))
sql = "SELECT checkins.* FROM %s %s %s %s" % (
tables, conditions, order_by, limit)
sql = "SELECT %s.* FROM %s %s %s %s" \
% (commits_table, tables, conditions, order_by, limit)
return sql
def RunQuery(self, query):
sql = self.CreateSQLQueryString(query)
sql = self.CreateSQLQueryString(query, 1)
cursor = self.db.cursor()
cursor.execute(sql)
query.SetExecuted()
row_count = 0
while 1:
row = cursor.fetchone()
if not row:
break
row_count = row_count + 1
if query.limit and (row_count > query.limit):
query.SetLimitReached()
break
(dbType, dbCI_When, dbAuthorID, dbRepositoryID, dbDirID,
dbFileID, dbRevision, dbStickyTag, dbBranchID, dbAddedLines,
@@ -409,8 +520,12 @@ class CheckinDatabase:
if file_id == None:
return None
sql = "SELECT * FROM checkins WHERE "\
" repositoryid=%s AND dirid=%s AND fileid=%s AND revision=%s"
sql = "SELECT * FROM %s WHERE "\
" repositoryid=%%s "\
" AND dirid=%%s"\
" AND fileid=%%s"\
" AND revision=%%s"\
% (self.GetCommitsTable())
sql_args = (repository_id, dir_id, file_id, commit.GetRevision())
cursor = self.db.cursor()
@@ -424,6 +539,75 @@ class CheckinDatabase:
return commit
def sql_delete(self, table, key, value, keep_fkey = None):
sql = "DELETE FROM %s WHERE %s=%%s" % (table, key)
sql_args = (value, )
if keep_fkey:
sql += " AND %s NOT IN (SELECT %s FROM %s WHERE %s = %%s)" \
% (key, keep_fkey, self.GetCommitsTable(), keep_fkey)
sql_args = (value, value)
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
def sql_purge(self, table, key, fkey, ftable):
sql = "DELETE FROM %s WHERE %s NOT IN (SELECT %s FROM %s)" \
% (table, key, fkey, ftable)
cursor = self.db.cursor()
cursor.execute(sql)
def PurgeRepository(self, repository):
rep_id = self.GetRepositoryID(repository, auto_set=0)
if not rep_id:
raise UnknownRepositoryError("Unknown repository '%s'"
% (repository))
if (self._version >= 1):
self.sql_delete('repositories', 'id', rep_id)
self.sql_purge('commits', 'repositoryid', 'id', 'repositories')
self.sql_purge('files', 'id', 'fileid', 'commits')
self.sql_purge('dirs', 'id', 'dirid', 'commits')
self.sql_purge('branches', 'id', 'branchid', 'commits')
self.sql_purge('descs', 'id', 'descid', 'commits')
self.sql_purge('people', 'id', 'whoid', 'commits')
else:
sql = "SELECT * FROM checkins WHERE repositoryid=%s"
sql_args = (rep_id, )
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
checkins = []
while 1:
try:
(ci_type, ci_when, who_id, repository_id,
dir_id, file_id, revision, sticky_tag, branch_id,
plus_count, minus_count, description_id) = \
cursor.fetchone()
except TypeError:
break
checkins.append([file_id, dir_id, branch_id,
description_id, who_id])
#self.sql_delete('repositories', 'id', rep_id)
self.sql_delete('checkins', 'repositoryid', rep_id)
for checkin in checkins:
self.sql_delete('files', 'id', checkin[0], 'fileid')
self.sql_delete('dirs', 'id', checkin[1], 'dirid')
self.sql_delete('branches', 'id', checkin[2], 'branchid')
self.sql_delete('descs', 'id', checkin[3], 'descid')
self.sql_delete('people', 'id', checkin[4], 'whoid')
# Reset all internal id caches. We could be choosier here,
# but let's just be as safe as possible.
self._get_cache = {}
self._get_id_cache = {}
self._desc_id_cache = {}
class DatabaseVersionError(Exception):
pass
class UnknownRepositoryError(Exception):
pass
## the Commit class holds data on one commit, the representation is as
## close as possible to how it should be committed and retrieved to the
## database engine
@@ -471,10 +655,15 @@ class Commit:
return self.__revision
def SetTime(self, gmt_time):
self.__gmt_time = float(gmt_time)
if gmt_time is None:
### We're just going to assume that a datestamp of The Epoch
### ain't real.
self.__gmt_time = 0.0
else:
self.__gmt_time = float(gmt_time)
def GetTime(self):
return self.__gmt_time
return self.__gmt_time and self.__gmt_time or None
def SetAuthor(self, author):
self.__author = author
@@ -594,8 +783,9 @@ class QueryEntry:
self.data = data
self.match = match
## CheckinDatabaseQueryData is a object which contains the search parameters
## for a query to the CheckinDatabase
## CheckinDatabaseQuery is an object which contains the search
## parameters for a query to the Checkin Database and -- after the
## query is executed -- the data returned by the query.
class CheckinDatabaseQuery:
def __init__(self):
## sorting
@@ -607,6 +797,7 @@ class CheckinDatabaseQuery:
self.directory_list = []
self.file_list = []
self.author_list = []
self.comment_list = []
## date range in DBI 2.0 timedate objects
self.from_date = None
@@ -614,7 +805,8 @@ class CheckinDatabaseQuery:
## limit on number of rows to return
self.limit = None
self.limit_reached = 0
## list of commits -- filled in by CVS query
self.commit_list = []
@@ -622,6 +814,9 @@ class CheckinDatabaseQuery:
## are added
self.commit_cb = None
## has this query been run?
self.executed = 0
def SetRepository(self, repository, match = "exact"):
self.repository_list.append(QueryEntry(repository, match))
@@ -637,6 +832,9 @@ class CheckinDatabaseQuery:
def SetAuthor(self, author, match = "exact"):
self.author_list.append(QueryEntry(author, match))
def SetComment(self, comment, match = "exact"):
self.comment_list.append(QueryEntry(comment, match))
def SetSortMethod(self, sort):
self.sort = sort
@@ -664,6 +862,20 @@ class CheckinDatabaseQuery:
def AddCommit(self, commit):
self.commit_list.append(commit)
def SetExecuted(self):
self.executed = 1
def SetLimitReached(self):
self.limit_reached = 1
def GetLimitReached(self):
assert self.executed
return self.limit_reached
def GetCommitList(self):
assert self.executed
return self.commit_list
##
## entrypoints
@@ -682,7 +894,7 @@ def ConnectDatabase(cfg, readonly=0):
user = cfg.cvsdb.user
passwd = cfg.cvsdb.passwd
db = CheckinDatabase(cfg.cvsdb.host, cfg.cvsdb.port, user, passwd,
cfg.cvsdb.database_name, cfg.cvsdb.row_limit)
cfg.cvsdb.database_name)
db.Connect()
return db
@@ -695,7 +907,8 @@ def GetCommitListFromRCSFile(repository, path_parts, revision=None):
directory = string.join(path_parts[:-1], "/")
file = path_parts[-1]
revs = repository.itemlog(path_parts, revision, {"cvs_pass_rev": 1})
revs = repository.itemlog(path_parts, revision, vclib.SORTBY_DEFAULT,
0, 0, {"cvs_pass_rev": 1})
for rev in revs:
commit = CreateCommit()
commit.SetRepository(repository.rootpath)

View File

@@ -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

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]
@@ -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,58 @@ 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 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)
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 +839,26 @@ 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):
return s
_printers = {
FORMAT_RAW : _raw_printer,
FORMAT_HTML : _html_printer,
FORMAT_XML : _html_printer,
def _html_formatter(s):
return cgi.escape(s)
def _xml_formatter(s):
s = s.replace('&', '&#x26;')
s = s.replace('<', '&#x3C;')
s = s.replace('>', '&#x3E;')
return s
def _uri_formatter(s):
return urllib.quote(s)
_formatters = {
FORMAT_RAW : _raw_formatter,
FORMAT_HTML : _html_formatter,
FORMAT_XML : _xml_formatter,
FORMAT_URI : _uri_formatter,
}
# --- standard test environment ---

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 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
@@ -131,194 +131,6 @@ def popen(cmd, args, mode, capture_err=1):
# 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."
@@ -369,7 +181,7 @@ class _pipe:
exit = os.waitpid(pid, 0)[1]
return exit
else:
return os.waitpid(self.child_pid, 0)[1]
return os.waitpid(self.child_pid, 0)[1]
return None
def __getattr__(self, name):

View File

@@ -25,10 +25,10 @@ import time
import cvsdb
import viewvc
import vclib
import ezt
import debug
import urllib
import fnmatch
class FormData:
def __init__(self, form):
@@ -217,8 +217,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):
@@ -274,17 +275,60 @@ def prev_rev(rev):
r = r[:-2]
return string.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:
authorizer, params = cfg.get_authorizer_and_params_hack(cvsroot_name)
else:
authorizer = cfg.options.authorizer
params = cfg.get_authorizer_params()
# If CVSROOT_NAME isn't configured to use an authorizer, nothing
# is forbidden. If it's configured to use something other than
# the 'forbidden' authorizer, complain. Otherwise, check for
# forbiddenness per the PARAMS as expected.
if not authorizer:
return 0
if authorizer != 'forbidden':
raise Exception("The 'forbidden' authorizer is the only one supported "
"by this interface. The '%s' root is configured to "
"use a different one." % (cvsroot_name))
forbidden = params.get('forbidden', '')
forbidden = map(string.strip, filter(None, string.split(forbidden, ',')))
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 string.replace(server.escape(desc), '\n', '<br />') or ''
for commit in files:
parts = filter(None, string.split(commit.GetDirectory(), '/'))
if parts and cfg.options.hide_cvsroot and parts[0] == 'CVSROOT':
repository = commit.GetRepository()
directory = commit.GetDirectory()
cvsroot_name = cvsroots.get(repository)
## find the module name (if any)
try:
module = filter(None, string.split(directory, '/'))[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()
@@ -295,22 +339,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()])
## skip forbidden files
if cfg.is_forbidden(cvsroot_name,
filter(None, string.split(file, "/")), vclib.FILE):
continue
## if we couldn't find the cvsroot path configured in the
## viewvc.conf file, then don't make the link
if cvsroot_name:
## 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)
@@ -338,23 +378,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)
query = form_to_cvsdb_query(cfg, form_data)
db = cvsdb.ConnectDatabaseReadOnly(cfg)
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 = {}
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)
@@ -377,7 +421,7 @@ def run_query(server, cfg, form_data, viewvc_link):
return len(commit.files) > 0
commits = filter(_only_with_files, commits)
return commits
return commits, row_limit_reached
def main(server, cfg, viewvc_link):
try:
@@ -386,15 +430,19 @@ def main(server, cfg, viewvc_link):
form_data = FormData(form)
if form_data.valid:
commits = run_query(server, cfg, form_data, viewvc_link)
commits, row_limit_reached = run_query(server, cfg,
form_data, viewvc_link)
query = None
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 = ezt.TemplateData({
'cfg' : cfg,
'address' : cfg.general.address,
'vsn' : viewvc.__version__,
@@ -403,29 +451,21 @@ def main(server, cfg, viewvc_link):
'directory' : server.escape(form_data.directory),
'file' : server.escape(form_data.file),
'who' : server.escape(form_data.who),
'docroot' : cfg.options.docroot is None \
and viewvc_link + '/' + viewvc.docroot_magic_path \
or cfg.options.docroot,
'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),
'rss_href' : None,
}
if form_data.hours:
data['hours'] = form_data.hours
else:
data['hours'] = 2
server.header()
'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

View File

@@ -23,8 +23,8 @@ 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
@@ -33,6 +33,7 @@ server = None
# that character as-is, and sometimes needs to embed escaped values
# into HTML attributes.
def escape(s):
s = str(s)
s = string.replace(s, '&', '&amp;')
s = string.replace(s, '>', '&gt;')
s = string.replace(s, '<', '&lt;')
@@ -171,8 +172,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)
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)
@@ -186,7 +186,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)
@@ -198,6 +198,63 @@ 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
global cgi
import cgi
def addheader(self, name, value):
self._headers.append((name, value))
def header(self, content_type='text/html; charset=UTF-8', status=None):
if not status:
status = "200 OK"
if not self.headerSent:
self.headerSent = True
self._headers.insert(0, ("Content-Type", content_type),)
self._wsgi_write = self._start_response("%s" % status, self._headers)
def redirect(self, url):
"""Redirect client to url. This discards any data that has been queued
to be sent to the user. But there should never by any anyway.
"""
self.addheader('Location', url)
self.header(status='301 Moved')
self._wsgi_write('This document is located <a href="%s">here</a>.' % url)
def getenv(self, name, value=None):
return self._environ.get(name, value)
def params(self):
return cgi.parse(environ=self._environ, fp=self._environ["wsgi.input"])
def FieldStorage(self, fp=None, headers=None, outerboundary="",
environ=os.environ, keep_blank_values=0, strict_parsing=0):
return cgi.FieldStorage(self._environ["wsgi.input"], headers,
outerboundary, self._environ, keep_blank_values,
strict_parsing)
def write(self, s):
self._wsgi_write(s)
def flush(self):
pass
def file(self):
return File(self)
class AspServer(ThreadedServer):
def __init__(self, Server, Request, Response, Application):
ThreadedServer.__init__(self)
@@ -229,7 +286,6 @@ class AspServer(ThreadedServer):
def redirect(self, url):
self.response.Redirect(url)
sys.exit()
def getenv(self, name, value = None):
ret = self.request.ServerVariables(name)()
@@ -312,8 +368,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()
% (url, url))
def getenv(self, name, value = None):
try:

60
lib/vcauth/__init__.py Normal file
View File

@@ -0,0 +1,60 @@
# -*-python-*-
#
# Copyright (C) 2006-2010 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
"""Generic API for implementing authorization checks employed by ViewVC."""
import string
import vclib
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,53 @@
# -*-python-*-
#
# Copyright (C) 2006-2010 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
import vcauth
import vclib
import fnmatch
import string
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
"""A simple top-level module authorizer."""
def __init__(self, username, params={}):
forbidden = params.get('forbidden', '')
self.forbidden = map(string.strip,
filter(None, string.split(forbidden, ',')))
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,65 @@
# -*-python-*-
#
# Copyright (C) 2008-2010 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
import vcauth
import vclib
import fnmatch
import string
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(string.strip(x)),
filter(None, string.split(forbidden, ',')))
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 + '/' + string.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,270 @@
# -*-python-*-
#
# Copyright (C) 2006-2011 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 string
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.upper()
elif self.force_username_case == "lower":
self.username = username.lower()
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 = string.split(cp.get('groups', groupname), ',')
for entry in entries:
entry = string.strip(entry)
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 = string.strip(user)
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 = string.find(cp.get(section, user), '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 = string.split(section, ':', 1)
if name == rootname:
root_sections.append(section)
continue
# Check for a specific access determination.
allow, deny = _process_access_section(section)
# If we got an explicit access determination for this path and this
# USERNAME, record it.
if allow or deny:
if path != '/':
path = '/' + string.join(filter(None, string.split(path, '/')), '/')
paths_for_root[path] = allow
# Okay. Superimpose those root-specific values now.
for section in root_sections:
# Get the path again.
name, path = string.split(section, ':', 1)
# Check for a specific access determination.
allow, deny = _process_access_section(section)
# If we got an explicit access determination for this path and this
# USERNAME, record it.
if allow or deny:
if path != '/':
path = '/' + string.join(filter(None, string.split(path, '/')), '/')
paths_for_root[path] = allow
# If the root isn't readable, there's no point in caring about all
# the specific paths the user can't see. Just point the rootname
# to a None paths dictionary.
root_is_readable = 0
for path in paths_for_root.keys():
if paths_for_root[path]:
root_is_readable = 1
break
if not root_is_readable:
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 = '/' + string.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-2011 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
@@ -27,11 +27,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 +76,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 +86,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 +109,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 +123,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 +133,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
@@ -120,26 +173,46 @@ class Repository:
def annotate(self, path_parts, rev):
"""Return a list of annotate file content lines and a revision.
The annotated lines are an collection of objects with the
following addressable members:
The result is a list of Annotation objects, sorted by their
line_number components.
"""
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
def revinfo(self, rev):
"""Return information about a global revision
These object are sort by their line_number components.
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
"""
# ======================================================================
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 +220,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,16 +238,69 @@ 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
@@ -181,6 +308,7 @@ class ItemNotFound(Error):
if type(path) in (types.TupleType, types.ListType):
path = string.join(path, '/')
Error.__init__(self, path)
class InvalidRevision(Error):
def __init__(self, revision=None):
if revision is None:
@@ -188,6 +316,9 @@ class InvalidRevision(Error):
else:
Error.__init__(self, "Invalid revision " + str(revision))
class NonTextualFileContents(Error):
pass
# ======================================================================
# Implementation code used by multiple vclib modules
@@ -200,12 +331,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=-1')
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=-1')
else:
args.append('--unified=%i' % options['context'])
else:
args.append('-u')
elif type == SIDE_BY_SIDE:
@@ -226,14 +363,14 @@ 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
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")
self.fp = popen.popen(diff_cmd, args, "r")
def read(self, bytes):
return self.fp.read(bytes)
@@ -262,3 +399,26 @@ 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)
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-2008 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -9,343 +9,35 @@
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
"""
This is a Version Control library driver for locally accessible cvs-repositories.
"""
import os
import string
import re
import cStringIO
import tempfile
import vclib
import rcsparse
import blame
### The functionality shared with bincvs should probably be moved to a
### separate module
from vclib.bincvs import CVSRepository, Revision, Tag, \
_file_log, _log_path
class CCVSRepository(CVSRepository):
def dirlogs(self, path_parts, rev, entries, options):
"""see vclib.Repository.dirlogs docstring
rev can be a tag name or None. if set only information from revisions
matching the tag will be retrieved
Option values recognized by this implementation:
cvs_subdirs
boolean. true to fetch logs of the most recently modified file in each
subdirectory
Option values returned by this implementation:
cvs_tags, cvs_branches
lists of tag and branch names encountered in the directory
"""
subdirs = options.get('cvs_subdirs', 0)
dirpath = self._getpath(path_parts)
alltags = { # all the tags seen in the files of this dir
'MAIN' : '',
'HEAD' : '1.1'
}
for entry in entries:
entry.rev = entry.date = entry.author = entry.dead = entry.log = None
path = _log_path(entry, dirpath, subdirs)
if path:
entry.path = path
try:
rcsparse.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
class COSink(MatchingSink):
def __init__(self, rev):
MatchingSink.__init__(self, rev)
def canonicalize_rootpath(rootpath):
return os.path.normpath(rootpath)
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 expand_root_parent(parent_path):
# Each subdirectory of PARENT_PATH that contains a child
# "CVSROOT/config" is added the set of returned roots. Or, if the
# PARENT_PATH itself contains a child "CVSROOT/config", then all its
# subdirectories are returned as roots.
roots = {}
subpaths = os.listdir(parent_path)
cvsroot = os.path.exists(os.path.join(parent_path, "CVSROOT", "config"))
for rootname in subpaths:
rootpath = os.path.join(parent_path, rootname)
if cvsroot \
or (os.path.exists(os.path.join(rootpath, "CVSROOT", "config"))):
roots[rootname] = canonicalize_rootpath(rootpath)
return roots
def 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
def CVSRepository(name, rootpath, authorizer, utilities, use_rcsparse):
rootpath = canonicalize_rootpath(rootpath)
if use_rcsparse:
import ccvs
return ccvs.CCVSRepository(name, rootpath, authorizer, utilities)
else:
import bincvs
return bincvs.BinCVSRepository(name, rootpath, authorizer, utilities)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -13,6 +13,7 @@
"Version Control lib driver for locally accessible cvs-repositories."
import vclib
import vcauth
import os
import os.path
import sys
@@ -25,50 +26,96 @@ import time
import compat
import popen
class CVSRepository(vclib.Repository):
def __init__(self, name, rootpath):
class BaseCVSRepository(vclib.Repository):
def __init__(self, name, rootpath, authorizer, utilities):
if not os.path.isdir(rootpath):
raise vclib.ReposNotFound(name)
raise vclib.ReposNotFound(name)
self.name = name
self.rootpath = rootpath
self.auth = authorizer
self.utilities = utilities
# 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."
% (string.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
@@ -88,48 +135,61 @@ 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, "/")
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."
% (string.join(path_parts, "/")))
rcsfile = self.rcsfile(path_parts, 1)
return os.access(rcsfile, os.X_OK)
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)
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."
% (string.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:
@@ -189,11 +249,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."
% (string.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)
branches = options['cvs_branches'] = []
tags = options['cvs_tags'] = []
for name, rev in alltags.items():
@@ -202,7 +267,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 +287,10 @@ 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."
% (string.join(path_parts, "/")))
# Invoke rlog
rcsfile = self.rcsfile(path_parts, 1)
if rev and options.get('cvs_pass_rev', 0):
@@ -230,7 +299,7 @@ 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 = []
@@ -239,26 +308,42 @@ class BinCVSRepository(CVSRepository):
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
if 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):
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file."
% (string.join(path_parts, "/")))
from vclib.ccvs import blame
source = blame.BlameSource(self.rcsfile(path_parts, 1), rev)
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 +351,13 @@ class BinCVSRepository(CVSRepository):
ignore_keyword_subst - boolean, ignore keyword substitution
"""
if self.itemtype(path_parts1, rev1) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file."
% (string.join(path_parts1, "/")))
if self.itemtype(path_parts2, rev2) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file."
% (string.join(path_parts2, "/")))
args = vclib._diff_args(type, options)
if options.get('ignore_keyword_subst', 0):
args.append('-kk')
@@ -286,15 +378,16 @@ class BinCVSRepository(CVSRepository):
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 +400,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
@@ -597,13 +698,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
taginfo = { } # tag name => number
lockinfo = { } # revision => locker
state = 0 # 0 = base, 1 = parsing symbols, 2 = parsing locks
eof = None
while 1:
@@ -613,24 +715,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, ':'))
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(string.strip, string.split(line, ':'))
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
@@ -659,7 +772,7 @@ 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+([^;]+);'
@@ -759,7 +872,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,6 +903,10 @@ def _file_log(revs, taginfo, cur_branch, filter):
# 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
@@ -836,7 +953,7 @@ def _file_log(revs, taginfo, cur_branch, filter):
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):
alltags = { # all the tags seen in the files of this dir
'MAIN' : '',
'HEAD' : '1.1'
@@ -851,14 +968,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
@@ -878,7 +996,8 @@ 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
@@ -917,16 +1036,16 @@ 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
@@ -966,13 +1085,16 @@ 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:
_skip_file(rlog)
@@ -1084,6 +1206,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-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
#
# By using this file, you agree to the terms and conditions set forth in
@@ -31,6 +31,7 @@ import re
import time
import math
import rcsparse
import vclib
class CVSParser(rcsparse.Sink):
# Precompiled regular expressions
@@ -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']:
@@ -447,8 +448,7 @@ class BlameSource:
author = self.parser.revision_author[rev]
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 +456,3 @@ class BlameSource:
class BlameSequencingError(Exception):
pass
class _item:
def __init__(self, **kw):
vars(self).update(kw)

398
lib/vclib/ccvs/ccvs.py Normal file
View File

@@ -0,0 +1,398 @@
# -*-python-*-
#
# Copyright (C) 1999-2011 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 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 bincvs import BaseCVSRepository, Revision, Tag, _file_log, _log_path, _logsort_date_cmp, _logsort_rev_cmp
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."
% (string.join(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))
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."
% (string.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 self.itemtype(path_parts1, rev1) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file."
% (string.join(path_parts1, "/")))
if self.itemtype(path_parts2, rev2) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file."
% (string.join(path_parts2, "/")))
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, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
r2 = self.itemlog(path_parts2, rev2, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
info1 = (self.rcsfile(path_parts1, root=1, v=0), r1.date, r1.string)
info2 = (self.rcsfile(path_parts2, root=1, v=0), r2.date, r2.string)
diff_args = vclib._diff_args(type, options)
return vclib._diff_fp(temp1, temp2, info1, info2,
self.utilities.diff or 'diff', diff_args)
def annotate(self, path_parts, rev=None):
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file."
% (string.join(path_parts, "/")))
source = blame.BlameSource(self.rcsfile(path_parts, 1), rev)
return source, source.revision
def revinfo(self, rev):
raise vclib.UnsupportedFeature
def openfile(self, path_parts, rev, options):
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file."
% (string.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(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
self.lockinfo = { }
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 set_locker(self, rev, locker):
self.lockinfo[rev] = locker
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")
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 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.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 = string.split(text, '\n')
idx = 0
while idx < len(lines):
command = lines[idx]
dmatch = self.d_command.match(command)
idx = idx + 1
if dmatch:
deled = deled + string.atoi(dmatch.group(2))
else:
amatch = self.a_command.match(command)
if amatch:
count = string.atoi(amatch.group(2))
added = added + count
idx = idx + count
elif command:
raise "error while parsing deltatext: %s" % command
if len(rev.number) == 2:
rev.next_changed = changed and "+%i -%i" % (deled, added)
else:
rev.changed = changed and "+%i -%i" % (added, deled)
class StreamText:
d_command = re.compile('^d(\d+)\\s(\\d+)')
a_command = re.compile('^a(\d+)\\s(\\d+)')
def __init__(self, text):
self.text = string.split(text, "\n")
def command(self, cmd):
adjust = 0
add_lines_remaining = 0
diffs = string.split(cmd, "\n")
if diffs[-1] == "":
del diffs[-1]
if len(diffs) == 0:
return
if diffs[0] == "":
del diffs[0]
for command in diffs:
if add_lines_remaining > 0:
# Insertion lines from a prior "a" command
self.text.insert(start_line + adjust, command)
add_lines_remaining = add_lines_remaining - 1
adjust = adjust + 1
continue
dmatch = self.d_command.match(command)
amatch = self.a_command.match(command)
if dmatch:
# "d" - Delete command
start_line = string.atoi(dmatch.group(1))
count = string.atoi(dmatch.group(2))
begin = start_line + adjust - 1
del self.text[begin:begin + count]
adjust = adjust - count
elif amatch:
# "a" - Add command
start_line = string.atoi(amatch.group(1))
count = string.atoi(amatch.group(2))
add_lines_remaining = count
else:
raise RuntimeError, 'Error parsing diff commands'
def secondnextdot(s, start):
# find the position the second dot after the start index.
return string.find(s, '.', string.find(s, '.', start) + 1)
class COSink(MatchingSink):
def __init__(self, rev):
MatchingSink.__init__(self, rev)
def set_head_revision(self, revision):
self.head = Revision(revision)
self.last = None
self.sstext = None
def admin_completed(self):
MatchingSink.admin_completed(self)
if self.find_tag is None:
raise vclib.InvalidRevision(self.find)
def set_revision_info(self, revision, log, text):
tag = self.find_tag
rev = Revision(revision)
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-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -12,45 +12,55 @@
"""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):
def define_tag(self, name, revision):
pass
def set_locker(self, revision, locker):
pass
def set_locking(self, mode):
"""Used to signal locking mode.
Called with mode argument 'strict' if strict locking
Not called when no locking used."""
pass
def set_locker(self, revision, locker):
pass
def set_comment(self, comment):
pass
def set_description(self, description):
def set_expansion(self, mode):
pass
def admin_completed(self):
pass
def define_revision(self, revision, timestamp, author, state,
branches, next):
pass
def set_revision_info(self, revision, log, text):
pass
def admin_completed(self):
pass
def tree_completed(self):
pass
def set_description(self, description):
pass
def set_revision_info(self, revision, log, text):
pass
def parse_completed(self):
pass
@@ -62,97 +72,201 @@ 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 timestamp
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'
timestamp = calendar.timegm(tuple(date_fields) + (0, 0, 0,))
# 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@;
# 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 +277,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')

View File

@@ -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

@@ -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-2009 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -10,746 +10,59 @@
#
# -----------------------------------------------------------------------
"Version Control lib driver for locally accessible Subversion repositories"
"Version Control lib driver for Subversion repositories"
import vclib
import os
import os.path
import stat
import string
import cStringIO
import signal
import shutil
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_rootpath(rootpath):
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)
import svn.core
return svn.core.svn_path_canonicalize(rootpath)
except:
if os.name == 'posix':
rootpath_lower = rootpath.lower()
if rootpath_lower in ['file://localhost',
'file://localhost/',
'file://',
'file:///'
]:
return '/'
if rootpath_lower.startswith('file://localhost/'):
return os.path.normpath(urllib.unquote(rootpath[16:]))
elif rootpath_lower.startswith('file:///'):
return os.path.normpath(urllib.unquote(rootpath[7:]))
if re.search(_re_url, rootpath):
return rootpath.rstrip('/')
return os.path.normpath(rootpath)
def last_rev(svnrepos, path, peg_revision, limit_revision=None):
"""Given PATH, known to exist in PEG_REVISION, find the youngest
revision older than, or equal to, LIMIT_REVISION in which path
exists. Return that revision, and the path at which PATH exists in
that revision."""
# Here's the plan, man. In the trivial case (where PEG_REVISION is
# the same as LIMIT_REVISION), this is a no-brainer. If
# LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
# history tracing code to find the right location. If, however,
# LIMIT_REVISION is younger than PEG_REVISION, we suffer from
# Subversion's lack of forward history searching. Our workaround,
# ugly as it may be, involves a binary search through the revisions
# between PEG_REVISION and LIMIT_REVISION to find our last live
# revision.
peg_revision = svnrepos._getrev(peg_revision)
limit_revision = svnrepos._getrev(limit_revision)
try:
if peg_revision == limit_revision:
return peg_revision, path
elif peg_revision > limit_revision:
fsroot = svnrepos._getroot(peg_revision)
history = fs.node_history(fsroot, path, 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)
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()
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 _get_history(svnrepos, full_name, rev, options={}):
if svnrepos.youngest == 0:
return {}
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)
# 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
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
def get_revision_info(svnrepos, rev):
fsroot = svnrepos._getroot(rev)
# Get the changes for the revision
editor = repos.ChangeCollector(svnrepos.fs_ptr, fsroot, svnrepos.pool)
e_ptr, e_baton = delta.make_editor(editor, svnrepos.pool)
repos.svn_repos_replay(fsroot, e_ptr, e_baton, svnrepos.pool)
changes = editor.get_changes()
changedpaths = {}
# Copy the Subversion changes into a new hash, converting them into
# ChangedPath objects.
for path in changes.keys():
change = changes[path]
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 = 'modified'
if not change.path:
action = 'deleted'
elif change.added:
action = 'added'
replace_check_path = path
if change.base_path and change.base_rev:
replace_check_path = change.base_path
if changedpaths.has_key(replace_check_path) \
and changedpaths[replace_check_path].action == 'deleted':
action = 'replaced'
else:
if change.action == repos.CHANGE_ACTION_ADD:
action = 'added'
elif change.action == repos.CHANGE_ACTION_DELETE:
action = 'deleted'
elif change.action == repos.CHANGE_ACTION_REPLACE:
action = 'replaced'
else:
action = 'modified'
if (action == 'added' or action == 'replaced') \
and change.base_path \
and change.base_rev:
is_copy = 1
if change.item_kind == core.svn_node_dir:
pathtype = vclib.DIR
elif change.item_kind == core.svn_node_file:
pathtype = vclib.FILE
else:
pathtype = None
changedpaths[path] = ChangedPath(path, pathtype, change.prop_changes,
change.text_changed, change.base_path,
change.base_rev, action, is_copy)
# Actually, what we want is a sorted list of ChangedPath objects.
change_items = changedpaths.values()
change_items.sort(lambda a, b: _compare_paths(a.filename, b.filename))
# Now get the revision property info. Would use
# editor.get_root_props(), but something is broken there...
datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev, svnrepos.pool)
date = _datestr_to_date(datestr, svnrepos.pool)
return date, author, msg, change_items
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.
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 _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
# Do a little dance to get a URL that works in both Unix-y and
# Windows worlds.
rootpath = os.path.abspath(rootpath)
if rootpath and rootpath[0] != '/':
rootpath = '/' + rootpath
if os.sep != '/':
rootpath = string.replace(rootpath, os.sep, '/')
# Make a read-only temporary directory for Subversion to use as
# its runtime config dir. (Read-only because that will prevent
# Subversion from fleshing out all the default runtime config
# contents.)
self.config_dir = self._mkdtemp()
os.chmod(self.config_dir, stat.S_IRUSR | stat.S_IXUSR)
url = 'file://' + string.join([rootpath, fs_path], "/")
fp = popen.popen(svn_client_path,
("blame",
"-r%d" % int(rev),
"--non-interactive",
"--config-dir", self.config_dir,
"%s@%d" % (url, int(rev))),
'rb', 1)
self.fp = fp
def _mkdtemp(self):
### FIXME: When we require Python 2.3, this can go away.
for i in range(10):
dir = tempfile.mktemp()
try:
os.mkdir(dir, 0700)
return dir
except OSError, e:
if e.errno == errno.EEXIST:
continue # try again
raise
raise IOError, (errno.EEXIST, "No usable temporary directory name found")
def __getitem__(self, idx):
if idx == self.idx:
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
def __del__(self):
try:
if self.config_dir:
shutil.rmtree(self.config_dir)
except:
pass
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)

605
lib/vclib/svn/svn_ra.py Normal file
View File

@@ -0,0 +1,605 @@
# -*-python-*-
#
# Copyright (C) 1999-2011 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 time
import urllib
from svn_repos import Revision, SVNChangedPath, _datestr_to_date, _compare_paths, _path_parts, _cleanup_path, _rev2optrev, _fix_subversion_exception, _split_revprops
from svn import core, delta, client, wc, ra
### 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, cross_copies,
cb_func, ctx):
try:
client.svn_client_log4([url], start_rev, start_rev, end_rev,
log_limit, 1, not cross_copies, 0, None,
cb_func, ctx)
except AttributeError:
# Wrap old svn_log_message_receiver_t interface with a
# svn_log_entry_t one.
def cb_convert(paths, revision, author, date, message, pool):
class svn_log_entry_t:
pass
log_entry = svn_log_entry_t()
log_entry.changed_paths = paths
log_entry.revision = revision
log_entry.revprops = { core.SVN_PROP_REVISION_LOG : message,
core.SVN_PROP_REVISION_AUTHOR : author,
core.SVN_PROP_REVISION_DATE : date,
}
cb_func(log_entry, pool)
client.svn_client_log2([url], start_rev, end_rev, log_limit,
1, not cross_copies, cb_convert, ctx)
### END COMPATABILITY CODE ###
class LogCollector:
### TODO: Make this thing authz-aware
def __init__(self, path, show_all_logs, lockinfo):
# 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
def add_log(self, log_entry, pool):
paths = log_entry.changed_paths
revision = log_entry.revision
msg, author, date, revprops = _split_revprops(log_entry.revprops)
# Changed paths have leading slashes
changed_paths = 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:
entry = Revision(revision, date, author, msg, None, self.lockinfo,
self.path[1:], None, None)
self.logs.append(entry)
if this_path:
self.path = this_path
def temp_checkout(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.
# TODO: svn_cmdline_setup_auth_baton() is mo' better (when available)
core.svn_config_ensure(self.config_dir)
self.ctx = client.svn_client_create_context()
self.ctx.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(),
])
self.ctx.config = core.svn_config_get_config(self.config_dir)
if self.config_dir is not None:
core.svn_auth_set_parameter(self.ctx.auth_baton,
core.SVN_AUTH_PARAM_CONFIG_DIR,
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)
tmp_file = tempfile.mktemp()
stream = core.svn_stream_from_aprfile(tmp_file)
### rev here should be the last history revision of the URL
client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev), self.ctx)
core.svn_stream_close(stream)
return SelfCleanFP(tmp_file), self._get_last_history_rev(path_parts, 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
if vclib.check_path_access(self, path_parts + [name], kind, rev):
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]
if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
continue
dirent = dirents[entry.name]
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)
# Use ls3 to fetch the lock status for this item.
lockinfo = None
basename = path_parts and path_parts[-1] or ""
dirents, locks = list_directory(url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
if locks.has_key(basename):
lockinfo = locks[basename].owner
# 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)
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,
cross_copies, lc.add_log, self.ctx)
revs = lc.logs
revs.sort()
prev = None
for rev in revs:
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):
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)
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(vclib.Annotation(line, line_no+1, revision, prev_rev,
author, None))
client.svn_client_blame(url, _rev2optrev(1), _rev2optrev(rev),
_blame_cb, self.ctx)
return blame_data, rev
def revinfo(self, rev):
rev = self._getrev(rev)
cached_info = self._revinfo_cache.get(rev)
if not cached_info:
cached_info = self._revinfo_raw(rev)
self._revinfo_cache[rev] = cached_info
return tuple(cached_info)
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
p1 = self._getpath(path_parts1)
p2 = self._getpath(path_parts2)
r1 = self._getrev(rev1)
r2 = self._getrev(rev2)
if not vclib.check_path_access(self, path_parts1, vclib.FILE, rev1):
raise vclib.ItemNotFound(path_parts1)
if not vclib.check_path_access(self, path_parts2, vclib.FILE, rev2):
raise vclib.ItemNotFound(path_parts2)
args = vclib._diff_args(type, options)
def _date_from_rev(rev):
date, author, msg, revprops, changes = self.revinfo(rev)
return date
try:
temp1 = temp_checkout(self, p1, r1)
temp2 = temp_checkout(self, p2, r2)
info1 = p1, _date_from_rev(r1), r1
info2 = p2, _date_from_rev(r2), r2
return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == vclib.svn.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 _getpath(self, path_parts):
return string.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
return self.rootpath + '/' + urllib.quote(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."""
dir_url = self._geturl(path)
if path:
key = str(rev) + '/' + path
else:
key = str(rev)
dirents_locks = self._dirent_cache.get(key)
if not dirents_locks:
dirents, locks = list_directory(dir_url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
dirents_locks = [dirents, locks]
self._dirent_cache[key] = dirents_locks
return dirents_locks[0], dirents_locks[1]
def _get_last_history_rev(self, path_parts, rev):
url = self._geturl(self._getpath(path_parts))
optrev = _rev2optrev(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)
return revisions[0]
def _revinfo_raw(self, rev):
# return 5-tuple (date, author, msg, revprops, changes)
optrev = _rev2optrev(rev)
revs = []
def _log_cb(log_entry, pool, retval=revs):
### 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))
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,
}
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 (we 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 vclib.check_path_access(self, parts, vclib.FILE, base_rev):
is_copy = 0
base_path = None
base_rev = None
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 found_unreadable:
msg = None
if not found_readable:
author = None
date = None
revs.append([date, author, msg, revprops, changes])
client_log(self.rootpath, optrev, optrev, 1, 0, _log_cb, self.ctx)
return tuple(revs[0])
##--- 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)
return _cleanup_path(old_path)
def created_rev(self, path, rev):
# NOTE: We can't use svn_client_propget here because the
# interfaces in that layer strip out the properties not meant for
# human consumption (such as svn:entry:committed-rev, which we are
# using here to get the created revision of PATH@REV).
kind = ra.svn_ra_check_path(self.ra_session, path, rev)
if kind == core.svn_node_none:
raise vclib.ItemNotFound(_path_parts(path))
elif kind == core.svn_node_dir:
props = get_directory_props(self.ra_session, path, rev)
elif kind == core.svn_node_file:
fetched_rev, props = ra.svn_ra_get_file(self.ra_session, path, rev, None)
return int(props.get(core.SVN_PROP_ENTRY_COMMITTED_REV,
SVN_INVALID_REVNUM))
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

919
lib/vclib/svn/svn_repos.py Normal file
View File

@@ -0,0 +1,919 @@
# -*-python-*-
#
# Copyright (C) 1999-2011 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 string
import cStringIO
import signal
import time
import tempfile
import popen
import re
from svn import fs, repos, core, client, delta
### 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]
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, string.split(path, '/'))
def _cleanup_path(path):
"""Return a cleaned-up Subversion filesystem path"""
return string.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)
if rootpath and rootpath[0] != '/':
rootpath = '/' + rootpath
if os.sep != '/':
rootpath = string.replace(rootpath, os.sep, '/')
return 'file://' + string.join([rootpath, path], "/")
# Given a dictionary REVPROPS of revision properties, pull special
# ones out of them and return a 4-tuple containing the log message,
# the author, the date (converted from the date string property), and
# a dictionary of any/all other revprops.
def _split_revprops(revprops):
if not revprops:
return None, None, None, {}
special_props = []
for prop in core.SVN_PROP_REVISION_LOG, \
core.SVN_PROP_REVISION_AUTHOR, \
core.SVN_PROP_REVISION_DATE:
if revprops.has_key(prop):
special_props.append(revprops[prop])
del(revprops[prop])
else:
special_props.append(None)
msg, author, datestr = tuple(special_props)
date = _datestr_to_date(datestr)
return msg, author, date, revprops
def _datestr_to_date(datestr):
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 = string.rfind(test_path, '/')
if off < 0:
break
test_path = test_path[0:off]
if test_path in paths:
copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, test_path)
if copyfrom_rev >= 0 and copyfrom_path:
found = 1
break
if not found:
return
self.histories.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, config_dir):
self.idx = -1
self.first_rev = first_rev
self.blame_data = []
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.blame2(local_url, _rev2optrev(rev), _rev2optrev(first_rev),
_rev2optrev(rev), 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
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.svn_client_path = utilities.svn or 'svn'
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):
# 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):
sys.exit(-1)
try:
signal.signal(signal.SIGTERM, _sigterm_handler)
except ValueError:
# This is probably "ValueError: signal only works in main
# thread", which will get thrown by the likes of mod_python
# when trying to install a signal handler from a thread that
# isn't the main one. We'll just not care.
pass
# Open the repository and init some other variables.
self.repos = repos.svn_repos_open(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):
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, 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={}):
p1 = self._getpath(path_parts1)
p2 = self._getpath(path_parts2)
r1 = self._getrev(rev1)
r2 = self._getrev(rev2)
if not vclib.check_path_access(self, path_parts1, vclib.FILE, rev1):
raise vclib.ItemNotFound(path_parts1)
if not vclib.check_path_access(self, path_parts2, vclib.FILE, rev2):
raise vclib.ItemNotFound(path_parts2)
args = vclib._diff_args(type, options)
def _date_from_rev(rev):
date, author, msg, revprops, changes = self._revinfo(rev)
return date
try:
temp1 = temp_checkout(self, p1, r1)
temp2 = temp_checkout(self, p2, r2)
info1 = p1, _date_from_rev(r1), r1
info2 = p2, _date_from_rev(r2), r2
return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.InvalidRevision
raise
def isexecutable(self, path_parts, rev):
props = self.itemprops(path_parts, rev) # does authz-check
return props.has_key(core.SVN_PROP_EXECUTABLE)
##--- helpers ---##
def _revinfo(self, rev, include_changed_paths=0):
"""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
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 hasattr(change, 'copyfrom_known') and change.copyfrom_known:
copyfrom_path = change.copyfrom_path
copyfrom_rev = change.copyfrom_rev
else:
copyfrom_rev, copyfrom_path = fs.copied_from(fsroot, path)
return copyfrom_path, copyfrom_rev
def _simple_auth_check(fsroot):
"""Return a 2-tuple: found_readable, found_unreadable."""
found_unreadable = found_readable = 0
if hasattr(fs, 'paths_changed2'):
changes = fs.paths_changed2(fsroot)
else:
changes = fs.paths_changed(fsroot)
paths = changes.keys()
for path in paths:
change = changes[path]
pathtype = None
if hasattr(change, 'node_kind'):
if change.node_kind == core.svn_node_file:
pathtype = vclib.FILE
elif change.node_kind == core.svn_node_dir:
pathtype = vclib.DIR
parts = _path_parts(path)
if pathtype is None:
# Figure out the pathtype so we can query the authz subsystem.
if change.change_kind == fs.path_change_delete:
# Deletions are annoying, because they might be underneath
# copies (make their previous location non-trivial).
prev_parts = parts
prev_rev = rev - 1
parent_parts = parts[:-1]
while parent_parts:
parent_path = '/' + self._getpath(parent_parts)
parent_change = changes.get(parent_path)
if not (parent_change and \
(parent_change.change_kind == fs.path_change_add or
parent_change.change_kind == fs.path_change_replace)):
del(parent_parts[-1])
continue
copyfrom_path, copyfrom_rev = \
_get_change_copyinfo(fsroot, parent_path, parent_change)
if copyfrom_path:
prev_rev = copyfrom_rev
prev_parts = _path_parts(copyfrom_path) + \
parts[len(parent_parts):]
break
del(parent_parts[-1])
pathtype = self._gettype(self._getpath(prev_parts), prev_rev)
else:
pathtype = self._gettype(self._getpath(parts), rev)
if vclib.check_path_access(self, parts, pathtype, rev):
found_readable = 1
copyfrom_path, copyfrom_rev = \
_get_change_copyinfo(fsroot, path, change)
if copyfrom_path and copyfrom_path != path:
parts = _path_parts(copyfrom_path)
if not vclib.check_path_access(self, parts, pathtype,
copyfrom_rev):
found_unreadable = 1
else:
found_unreadable = 1
if found_readable and found_unreadable:
break
return found_readable, found_unreadable
def _revinfo_helper(rev, include_changed_paths):
# Get the revision property info. (Would use
# editor.get_root_props(), but something is broken there...)
revprops = fs.revision_proplist(self.fs_ptr, rev)
msg, author, date, revprops = _split_revprops(revprops)
# 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 string.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 max(peg_revision, limit_revision), _cleanup_path(path)
history = fs.history_prev(history, 1)
return peg_revision, _cleanup_path(path)
else:
orig_id = fs.node_id(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

View File

@@ -1,452 +0,0 @@
# -*-python-*-
#
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
"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
import urllib
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:
retval = ra.svn_ra_get_dir(svnrepos.ra_session, full_name,
rev, svnrepos.pool)
if type(retval) == type([]) and len(retval) == 3:
props = retval[2]
else: # compat with older (broken) bindings
props = retval
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))
copyfrom_path = copyfrom_rev = this_path = None
if self.path in changed_paths:
this_path = self.path
change = paths[self.path]
if change.copyfrom_path:
this_path = change.copyfrom_path
copyfrom_path = change.copyfrom_path[1:]
copyfrom_rev = change.copyfrom_rev
for changed_path in changed_paths:
if changed_path != self.path:
# If a parent of our path was copied, our "next previous"
# (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:], copyfrom_path, copyfrom_rev)
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 = str(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._geturl(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=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 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):
path = self._getpath(path_parts)
rev = self._getrev(rev)
url = self._geturl(path)
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):
path = self._getpath(path_parts)
rev = self._getrev(rev)
url = self._geturl(path)
# 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))
cross_copies = options.get('svn_cross_copies', 0)
client.svn_client_log([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._geturl(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 _geturl(self, path=None):
if not path:
return self.rootpath
return self.rootpath + '/' + urllib.quote(path, "/*~")
def _get_dirents(self, path, rev):
dir_url = self._geturl(path)
if path:
key = str(rev) + '/' + path
else:
key = str(rev)
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

82
notes/authz-dev-TODO Normal file
View File

@@ -0,0 +1,82 @@
Here lie TODO items for the pluggable authz system:
* Subversion uses path privelege to determine visibility of revision
metadata. That logic is pretty Subversion-specific, so it feels like it
belongs outside the vcauth library as just a helper function in viewvc.py
or something. The algorithm is something like this (culled from the
CollabNet implementation, and not expected to work as edited):
# Subversion revision access levels
REVISION_ACCESS_NONE = 0
REVISION_ACCESS_PARTIAL = 1
REVISION_ACCESS_FULL = 2
def check_svn_revision_access(request, rev):
# Check our revision access cache first.
if request.rev_access_cache.has_key(rev):
return request.rev_access_cache[rev]
# Check our cached answer to the question "Does the user have
# an all-access or a not-at-all-access pass?"
if request.full_access is not None:
return request.full_access \
and REVISION_ACCESS_FULL or REVISION_ACCESS_NONE
# Get a list of paths changed in REV.
### FIXME: There outta be a vclib-complaint way to do this,
### as this won't work for vclib.svn_ra.
import svn.fs
rev_root = svn.fs.revision_root(self.repos.fs_ptr, rev)
changes = svn.fs.paths_changed(rev_root)
# Loop over the list of changed paths, asking the access question
# for each one. We'll track whether we've found any readable paths
# as well as any un-readable (non-authorized) paths, and quit
# checking as soon as we know our revision access level.
found_readable = 0
found_unreadable = 0
for path in changes.keys():
parts = _path_parts(path)
kind = request.repos.itemtype(parts, rev)
if kind == vclib.DIR:
access = request.auth.check_dir_access(parts, rev)
elif:
access = request.auth.check_file_access(parts, rev)
if access:
found_readable = 1
else:
found_unreadable = 1
# Optimization: if we've found at least one readable, and one
# unreadable, we needn't ask about any more paths.
if found_readable and found_unreadable:
break
# If there are paths but we can't read any of them, no access is
# granted.
if len(changes) and not found_readable:
request.rev_access_cache[rev] = REVISION_ACCESS_NONE
# If we found at least one unreadable path, partial access is
# granted.
elif found_unreadable:
request.rev_access_cache[rev] = REVISION_ACCESS_PARTIAL
# Finally, if there were no paths at all, or none of the existing
# ones were unreadable, grant full access.
else:
request.rev_access_cache[rev] = REVISION_ACCESS_FULL
return request.rev_access_cache[rev]
The problems are: where does one hang the revision access cache
so that it doesn't survive a given request? On the request, as
shown in the edited code above?
Can we actually get a good interface into the vcauth layer for
asking the all-access / no-access question? Obviously each vcauth
provider can cache that value for itself and use it as it deems
necessary, but ideally the revision access level question will
want to know if said auth provider was able to answer the question
and, if so, what the answer was.
Another off-the-wall idea -- let's just teach Subversion to do
this calculation as part of a libsvn_repos API.

BIN
notes/logo/viewvc-logo.odg Normal file

Binary file not shown.

BIN
notes/logo/viewvc-logo.pdf Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -24,10 +24,12 @@ numbers, and not literal):
Commit any modifications. NOTE: This step should not be necessary
for patch releases.
3. Verify that copyright years are correct in both the LICENSE.html
3. Verify that copyright years are correct in both the license-1.html
file and the source code.
4. Update and commit the 'CHANGES' file.
4. Update and commit the 'CHANGES' file, using any available crystal
balls or other forward-looking devices to take a stab at the
release date.
5. Test, test, test! There is no automatic testsuite available. So
just run with permuting different `viewvc.conf' settings... and
@@ -38,48 +40,76 @@ numbers, and not literal):
should exactly reflect what you wish to distribute and dub "the
release".
7. Edit the file 'lib/viewvc.py' and remove the "-dev" suffix from
7. Update your release branch working copy to HEAD.
svn up
8. Edit the file 'lib/viewvc.py' and remove the "-dev" suffix from
__version__. The remainder should be of the form "X.Y.Z", where X,
Y, and Z are positive integers. Do NOT commit this change.
Y, and Z are positive integers.
8. Update your working copy to HEAD, and tag the release:
*** Do NOT commit this change. ***
svn update
svn cp -m "Tag the X.Y.Z final release." . \
http://viewvc.tigris.org/svn/viewvc/tags/X.Y.Z
9. "Peg" the contributed templates externals definition to the
current HEAD revision:
9. Go into an empty directory and run the 'make-release' script:
svn pedit svn:externals .
(squeeze "-rBASE_REV", where BASE_REV is the current HEAD revision
number, between 'templates-contrib' and the target URL).
*** Do NOT commit this change. ***
10. Tag the release:
svn cp -m "Tag the X.Y.Z final release." . ^/tags/X.Y.Z
This will create a copy of the release branch, plus your local
modifications to the svn:externals property and lib/viewvc.py
file, to the tag location.
11. Revert the changes in your working copy.
svn revert -R .
12. Go into an empty directory and run the 'make-release' script:
tools/make-release viewvc-X.Y.Z tags/X.Y.Z
10. Verify the archive files:
13. Verify the archive files:
- do they have a LICENSE.html file?
- do they have necessary include documentation?
- do they *not* have unnecessary stuff?
- do they install and work correctly?
11. Upload the created archive files (tar.gz and zip) into the Files
14. Upload the created archive files (tar.gz and zip) into the Files
and Documents section of the Tigris.org project, and modify the
CHECKSUMS document there accordingly. Also, drop a copy of the
archive files into the root directory of the viewvc.org website
(unversioned).
CHECKSUMS document there accordingly:
12. Update the websites (both the viewvc.org/ and www/ ones) to refer
to the new release files.
http://viewvc.tigris.org/servlets/ProjectDocumentList?folderID=6004
13. Edit the file 'lib/viewvc.py' again, re-adding the "-dev" suffix
and incrementing the patch number assigned to the __version__
variable, and commit:
Also, drop a copy of the archive files into the root directory of
the viewvc.org website (unversioned).
15. On trunk, update the websites (both the viewvc.org/ and www/ ones)
to refer to the new release files, and copy the CHANGES for the
new release into trunk's CHANGES file.
16. Edit the file 'lib/viewvc.py' again, incrementing the patch number
assigned to the __version__ variable. Add a new empty block in
the branch's CHANGES file. Commit your changes:
svn ci -m "Begin a new release cycle."
14. Edit the Issue Tracker configuration options, adding a new Version
17. Edit the Issue Tracker configuration options, adding a new Version
for the just-released one, and a new Milestone for the next patch
(and possibly, minor or major) release. (For the Milestone sort
key, use a packed integer XXYYZZ: 1.0.3 == 10003, 2.11.4 == 21104.)
15. Write an announcement explaining all the cool new features and
post it to the announce@ list, to the project's News area, and to
other places interested in this sort of stuff, such as Freshmeat
(http://www.freshmeat.net).
http://viewvc.tigris.org/issues/editversions.cgi?component=viewvc&action=add
http://viewvc.tigris.org/issues/editmilestones.cgi?component=viewvc&action=add
18. Send to the announce@ list a message explaining all the cool new
features, and post similar announcements to other places interested
in this sort of stuff, such as Freshmeat (http://www.freshmeat.net).

View File

@@ -0,0 +1,78 @@
The following is an email from a developer who was integrating bzr
into ViewVC in which he shares some thoughts on how to further
abstract the version control system interactions into first-class APIs
in the vclib module.
Subject: Re: [ViewCVS-dev] difflib module
Date: Wed, 1 Jun 2005 16:59:10 -0800
From: "Johan Rydberg" <jrydberg@gnu.org>
To: "Michael Pilato" <cmpilato@collab.net>
Cc: <viewcvs-dev@lyra.org>
"C. Michael Pilato" <cmpilato@collab.net> writes:
>> I've tried to minimize the changes to the viewcvs.py, but of course
>> there are a few places where some things has to be altered.
>
> Well, if along the way, you have ideas about how to further abstract
> stuff into the vclib/ modules, please post.
I came up with a few as off now;
* Generalize revision counting; svn starts from 0, bzr starts from 1.
Can be done by a constant; request.repos.MIN_REVNO. For CVS I'm not
sure exactly what should be done. Right now this is only used in
view_revision_svn, so it is not a problem in the short term.
* Generalize view_diff;
* Have a repo-method diff(file1, rev1, file2, rev2, args) that returns
(date1, date2, fp). Means human_readbale_diff and raw_diff does not
have to parse dates. Good for VCS that does not have the date in
the diff. [### DONE ###]
* I'm not sure you should require GNU diff. Some VCS may use own
diff mechanisms (bzr uses difflib, _or_ GNU diff when needed.
Monotone uses its own, IIRC.)
* Generalize view_revision ;
* Have a method, revision_info(), which returns (date, author, msg,
changes) much like vclib.svn.get_revision_info. The CVS version
can raise a ViewCVSException. [### DONE ###]
* Establish a convention for renamed/copied files; current should
work good enough (change.base_path, change.base_rev) but action
string must be same for both svn and others.
* request.repos.rev (or .revision) should give the current revision
number of the repo. No need for this (from view_directory):
if request.roottype == 'svn':
revision = str(vclib.svn.created_rev(request.repos, request.where))
If svn needs the full name of the repo, why not give it when the
repo is created?
* request.repos.youngest vs vclib.svn.get_youngest_revision(REPO)
* More object oriented;
* The subversion backend is not really object oriented. viewcfg.py uses
a lot function from vclib.svn, which could instead be methods of the
Repository class. Example:
diffobj = vclib.svn.do_diff(request.repos, p1, int(rev1),
p2, int(rev2), args)
This should be a method of the repository;
diffobj = request.repos.do_diff(p1, rev1, ...)
I have identified the following functions;
- vclib.svn.created_rev
- vclib.svn.get_youngest_revision
- vclib.svn.date_from_rev
- vclib.svn.do_diff
- vclib.svn.get_revision_info

View File

@@ -1,43 +0,0 @@
[# setup page definitions][define page_title]Annotation of /[where][end][define help_href][docroot]/help_rootview.html[end][# end][include "include/header.ezt" "annotate"]
[include "include/file_header.ezt"]
<hr />
<p>
Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong></a>[else]<strong>[rev]</strong>[end] -
(<a href="[view_href]"><strong>view</strong></a>)
(<a href="[download_href]"><strong>download</strong></a>)
[if-any download_text_href](<a href="[download_text_href]"><strong>as text</strong></a>)[end]
[if-any orig_path]
<br />Original Path: <a href="[orig_href]"><em>[orig_path]</em></a>
[end]
</p>
[define class1]vc_row_even[end]
[define class2]vc_row_odd[end]
[define last_rev]0[end]
[define rowclass][class1][end]
<table cellspacing="0" cellpadding="0">
[for lines]
[is lines.rev last_rev]
[else]
[is rowclass class1]
[define rowclass][class2][end]
[else]
[define rowclass][class1][end]
[end]
[end]
<tr class="[rowclass]" id="l[lines.line_number]">
<td class="vc_blame_line">[lines.line_number] :</td>
<td class="vc_blame_author">[is lines.rev last_rev]&nbsp;[else][lines.author][end]</td>
<td class="vc_blame_rev">[is lines.rev last_rev]&nbsp;[else][if-any lines.diff_url]<a href="[lines.diff_url]">[end][lines.rev][if-any lines.diff_url]</a>[end][end]</td>
<td class="vc_blame_text">[lines.text]</td>
</tr>
[define last_rev][lines.rev][end]
[end]
</table>
[include "include/footer.ezt"]

View File

@@ -12,19 +12,24 @@
<pre class="vc_raw_diff">[raw_diff]</pre>
[end]
[define left_view_href][if-any left.prefer_markup][left.view_href][else][if-any left.download_href][left.download_href][end][end][end]
[define right_view_href][if-any right.prefer_markup][right.view_href][else][if-any right.download_href][right.download_href][end][end][end]
[if-any changes]
<table cellspacing="0" cellpadding="0">
<tr class="vc_diff_header">
<th style="width:6%;"></th>
<th style="width:47%; vertical-align:top;">
[is path_left path_right][else][path_left][end]
revision [rev_left], [date_left]
[if-any tag_left]<br />Tag: [tag_left][end]
[is left.path right.path][else][left.path][end]
revision [if-any left_view_href]<a href="[left_view_href]">[end][left.rev][if-any left_view_href]</a>[end][if-any left.author] by <em>[left.author]</em>[end],
[left.date]
[if-any left.tag]<br />Tag: [left.tag][end]
</th>
<th style="width:47%; vertical-align:top;">
[is path_left path_right][else][path_right][end]
revision [rev_right], [date_right]
[if-any tag_right]<br />Tag: [tag_right][end]
[is left.path right.path][else][right.path][end]
revision [if-any right_view_href]<a href="[right_view_href]">[end][right.rev][if-any right_view_href]</a>[end][if-any right.author] by <em>[right.author]</em>[end],
[right.date]
[if-any right.tag]<br />Tag: [right.tag][end]
</th>
</tr>
@@ -44,7 +49,7 @@
[else]
[is changes.type "add"]
<tr>
<td id="l[changes.line_number]">[if-any annotate_href]<a href="[annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_line_number" id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_empty">&nbsp;</td>
<td class="vc_diff_add">&nbsp;[changes.right]</td>
</tr>
@@ -59,7 +64,7 @@
[is changes.type "change"]
<tr>
[if-any changes.have_right]
<td id="l[changes.line_number]">[if-any annotate_href]<a href="[annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_line_number" id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
[else]
<td></td>
[end]
@@ -107,7 +112,7 @@
</tr>
[else]
<tr>
<td id="l[changes.line_number]">[if-any annotate_href]<a href="[annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_line_number" id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_nochange">&nbsp;[changes.left]</td>
<td class="vc_diff_nochange">&nbsp;[changes.right]</td>
</tr>
@@ -129,12 +134,12 @@
<thead>
<tr>
<th colspan="2">
[is path_left path_right][else][path_left][end]
Revision [rev_left]
[is left.path right.path][else][left.path][end]
Revision [left.rev]
</th>
<th colspan="2">
[is path_left path_right][else][path_right][end]
Revision [rev_right]
[is left.path right.path][else][right.path][end]
Revision [right.rev]
</th>
</tr>
</thead>
@@ -160,8 +165,8 @@
<table class="vc_idiff">
<thead>
<tr>
<th>r[rev_left]</th>
<th>r[rev_right]</th>
<th>r[left.rev]</th>
<th>r[right.rev]</th>
<th></th>
</tr>
</thead>
@@ -191,10 +196,11 @@
<td>
<form method="get" action="[diff_format_action]">
<div>
[diff_format_hidden_values]
[for diff_format_hidden_values]<input type="hidden" name="[diff_format_hidden_values.name]" value="[diff_format_hidden_values.value]"/>[end]
<select name="diff_format" onchange="submit()">
<option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
<option value="l" [is diff_format "l"]selected="selected"[end]>Long Colored Diff</option>
<option value="f" [is diff_format "f"]selected="selected"[end]>Full Colored Diff</option>
<option value="u" [is diff_format "u"]selected="selected"[end]>Unidiff</option>
<option value="c" [is diff_format "c"]selected="selected"[end]>Context Diff</option>
<option value="s" [is diff_format "s"]selected="selected"[end]>Side by Side</option>
@@ -212,7 +218,7 @@
<td>Legend:<br />
<table cellspacing="0" cellpadding="1">
<tr>
<td style="text-align:center;" class="vc_diff_remove">Removed from v.[rev_left]</td>
<td style="text-align:center;" class="vc_diff_remove">Removed from v.[left.rev]</td>
<td class="vc_diff_empty">&nbsp;</td>
</tr>
<tr>
@@ -220,7 +226,7 @@
</tr>
<tr>
<td class="vc_diff_empty">&nbsp;</td>
<td style="text-align:center;" class="vc_diff_add">Added in v.[rev_right]</td>
<td style="text-align:center;" class="vc_diff_add">Added in v.[right.rev]</td>
</tr>
</table>
</td>

View File

@@ -1,9 +1,9 @@
[include "include/dir_header.ezt"]
<table cellspacing="1" cellpadding="2">
<table cellspacing="1" cellpadding="2" class="fixed">
<thead>
<tr>
<th class="vc_header[is sortby "file"]_sort[end]" colspan="2">
<th style="width: 200px" class="vc_header[is sortby "file"]_sort[end]">
[if-any sortby_file_href]<a href="[sortby_file_href]#dirlist">File</a>[else]File[end]
[is sortby "file"]
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
@@ -11,6 +11,7 @@
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
</th>
<th style="width: 96px" class="vc_header"></th>
[if-any sortby_rev_href]
<th class="vc_header[is sortby "rev"]_sort[end]">
<a href="[sortby_rev_href]#dirlist">Last Change</a>
@@ -35,79 +36,92 @@
<tbody>
[if-any up_href]
<tr class="vc_row_odd">
<td>
<td style="width: 200px">
<a href="[up_href]">
<img src="[docroot]/images/back_small.png" alt="" width="16" height="16"
<img src="[docroot]/images/back_small.png" alt="" class="vc_icon"
/>&nbsp;Parent&nbsp;Directory</a>
</td>
<td>&nbsp;</td>
<td style="width: 96px; font-size: 0;"></td>
<td>&nbsp;</td>
</tr>
[end]
[for entries]
<tr class="vc_row_[if-index entries even]even[else]odd[end]">
<td>
<td style="width: 200px">
<a name="[entries.anchor]" href="[is entries.pathtype "dir"][entries.view_href][else][if-any entries.prefer_markup][entries.view_href][else][entries.download_href][end][end]" title="[is entries.pathtype "dir"]View Directory Contents[else][if-any entries.prefer_markup]View[else]Download[end] File Contents[end]">
<img src="[docroot]/images/[is entries.pathtype "dir"]dir[else][is entries.state "dead"]broken[else]text[end][end].png" alt="" width="16" height="16" />
<img src="[docroot]/images/[is entries.pathtype "dir"]dir[else][is entries.state "dead"]broken[else]text[end][end].png" alt="" class="vc_icon" />
[entries.name][is entries.pathtype "dir"]/[end]</a>
[if-any entries.lockinfo]<img src="[docroot]/images/lock.png" alt="locked" class="vc_icon" title="Locked by [entries.lockinfo]" />[end]
[is entries.state "dead"](dead)[end]
</td>
[if-any entries.errors]
<td colspan="2">[for entries.errors]<em>[entries.errors]</em>[end]</td>
[else]
<td style="width:1%; white-space: nowrap">
[define view_icon_link][end]
[define graph_icon_link][end]
[define download_icon_link][end]
[define annotate_icon_link][end]
[define log_icon_link][if-any entries.log_href]<a
href="[entries.log_href]"
title="View Log"><img
src="[docroot]/images/log.png"
alt="View Log"
class="vc_icon" /></a>[end][end]
[# Icon column. We might want to add more icons like a tarball
# icon for directories or a diff to previous icon for files. ]
[if-any entries.log_href]
<a href="[entries.log_href]"><img
src="[docroot]/images/log.png"
alt="View Log" width="16" height="16" /></a>
[is entries.pathtype "dir"]
[is roottype "cvs"]
[# no point in showing icon when there's only one to choose from]
[else]
[define view_icon_link]<a
href="[entries.view_href]"
title="View Directory Listing"><img
src="[docroot]/images/list.png"
alt="View Directory Listing"
class="vc_icon" /></a>[end]
[end]
[end]
[is entries.pathtype "dir"]
[is roottype "cvs"]
[# no point in showing icon when there's only one to choose from]
[else]
<a href="[entries.view_href]"><img
src="[docroot]/images/list.png"
alt="View Directory Listing" width="16" height="16" /></a>
[end]
[end]
[is entries.pathtype "file"]
[define view_icon_link][if-any entries.view_href]<a
href="[entries.view_href]"
title="View File"><img
src="[docroot]/images/view.png"
alt="View File"
class="vc_icon" /></a>[end][end]
[is entries.pathtype "file"]
[if-any entries.graph_href]
<a href="[entries.graph_href]"
[define graph_icon_link][if-any entries.graph_href]<a
href="[entries.graph_href]"
title="View Revision Graph"><img
src="[docroot]/images/cvsgraph_16x16.png"
alt="View Revision Graph" width="16" height="16" />
</a>
[end]
src="[docroot]/images/cvsgraph_16x16.png"
alt="View Revision Graph"
class="vc_icon" /></a>[end][end]
[if-any entries.view_href]
<a href="[entries.view_href]"><img
src="[docroot]/images/view.png"
alt="View File" width="16" height="16" /></a>
[end]
[define download_icon_link][if-any entries.download_href]<a
href="[entries.download_href]"
title="Download File"><img
src="[docroot]/images/download.png"
alt="Download File"
class="vc_icon" /></a>[end][end]
[if-any entries.download_href]
<a href="[entries.download_href]"><img
src="[docroot]/images/download.png"
alt="Download File" width="16" height="16" /></a>
[end]
[define annotate_icon_link][if-any entries.annotate_href]<a
href="[entries.annotate_href]"
title="Annotate File"><img
src="[docroot]/images/annotate.png"
alt="Annotate File"
class="vc_icon" /></a>[end][end]
[end]
<td style="width: 96px"
>[# Icon column. We might want to add more icons like a tarball
# icon for directories or a diff to previous icon for files.
# Make sure this sucker has no whitespace in it, or the fixed
# widthness of will suffer for large font sizes
][log_icon_link][view_icon_link][graph_icon_link][download_icon_link][annotate_icon_link]</td>
[if-any entries.annotate_href]
<a href="[entries.annotate_href]"><img
src="[docroot]/images/annotate.png"
alt="Annotate File" width="16" height="16" /></a>
[end]
[end]
</td>
<td>
[if-any entries.rev]
<strong>[if-any entries.revision_href]<a href="[entries.revision_href]">[entries.rev]</a>[else][entries.rev][end]</strong>
<strong>[if-any entries.revision_href]<a href="[entries.revision_href]" title="Revision [entries.rev]">[entries.rev]</a>[else][entries.rev][end]</strong>
([entries.ago] ago)
by <em>[entries.author]</em>:
[entries.log]

View File

@@ -53,7 +53,7 @@
<tr class="vc_row_odd">
<td colspan="2">
<a href="[up_href]">
<img src="[docroot]/images/back_small.png" alt="" width="16" height="16"
<img src="[docroot]/images/back_small.png" alt="" class="vc_icon"
/>&nbsp;Parent&nbsp;Directory</a>
</td>
<td>&nbsp;</td>
@@ -72,7 +72,7 @@
[else]
<a name="[entries.anchor]" href="[entries.log_href]" title="View file revision log">
[end]
<img src="[docroot]/images/[is entries.pathtype "dir"]dir[else][is entries.state "dead"]broken[else]text[end][end].png" alt="" width="16" height="16" />
<img src="[docroot]/images/[is entries.pathtype "dir"]dir[else][is entries.state "dead"]broken[else]text[end][end].png" alt="" class="vc_icon" />
[entries.name][is entries.pathtype "dir"]/[end]</a>
[is entries.state "dead"](dead)[end]
</td>
@@ -80,7 +80,7 @@
<td style="width:1%"><a href="[entries.graph_href]"
title="View Revision Graph"><img
src="[docroot]/images/cvsgraph_16x16.png"
alt="View Revision Graph" width="16" height="16" />
alt="View Revision Graph" class="vc_icon" />
</a></td>
[end]
[if-any entries.errors]
@@ -91,13 +91,16 @@
[is entries.pathtype "dir"]
<td>&nbsp;[if-any entries.rev]<a href="[entries.log_href]" title="View directory revision log"><strong>[entries.rev]</strong></a>[end]</td>
[else]
<td>&nbsp;[if-any entries.rev]<a href="[if-any entries.prefer_markup][entries.view_href][else][entries.download_href][end]" title="[if-any entries.prefer_markup]View[else]Download[end] file contents"><strong>[entries.rev]</strong></a>[end]</td>
[define rev_href][if-any entries.prefer_markup][entries.view_href][else][if-any entries.download_href][entries.download_href][end][end][end]
<td style="white-space: nowrap;">&nbsp;[if-any entries.rev][if-any rev_href]<a href="[rev_href]" title="[if-any entries.prefer_markup]View[else]Download[end] file contents">[end]<strong>[entries.rev]</strong>[if-any rev_href]</a>[end][end]
[if-any entries.lockinfo]<img src="[docroot]/images/lock.png" alt="locked" class="vc_icon" title="Locked by [entries.lockinfo]" />[end]
</td>
[end]
<td>&nbsp;[entries.ago]</td>
<td>&nbsp;[entries.author]</td>
[is cfg.options.show_logs "1"]
[if-any entries.log]
<td>&nbsp;[entries.log][is entries.pathtype "dir"][is roottype "cvs"]
[if-any entries.short_log]
<td>&nbsp;[entries.short_log][is entries.pathtype "dir"][is roottype "cvs"]
<em>(from [entries.log_file]/[entries.log_rev])</em>[end][end]</td>
[else]
<td>&nbsp;</td>

View File

@@ -4,31 +4,23 @@
<head>
<title>ViewVC Help: Directory View</title>
<link rel="stylesheet" href="help.css" type="text/css" />
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<div><a href="http://viewvc.org/index.html"><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
<table>
<col class="menu" />
<col />
<tr>
<td><a href="http://viewvc.org/index.html"><img
src="images/logo.png" alt="ViewVC logotype" /></a>
</td>
<td>
<h1>ViewVC Help: Directory View</h1>
</td>
</tr>
<tr><td>
<h3>Help</h3>
<a href="help_rootview.html">General</a><br />
<strong>Directory&nbsp;View</strong><br />
<a href="help_log.html">Log&nbsp;View</a><br />
<a href="help_query.html">Query&nbsp;Database</a><br />
</td><td>
<h3>Internet</h3>
<a href="http://viewvc.org/index.html">Home</a><br />
<a href="http://viewvc.org/upgrading.html">Upgrading</a><br />
<a href="http://viewvc.org/contributing.html">Contributing</a><br />
<a href="http://viewvc.org/license-1.html">License</a><br />
</td><td colspan="2">
<h1>ViewVC Help: Directory View</h1>
<p>The directory listing view should be a familiar sight to any
computer user. It shows the path of the current directory being viewed

View File

@@ -4,32 +4,24 @@
<head>
<title>ViewVC Help: Log View</title>
<link rel="stylesheet" href="help.css" type="text/css" />
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<div><a href="http://viewvc.org/index.html"><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
<table>
<col class="menu" />
<col />
<tr>
<td><a href="http://viewvc.org/index.html"><img
src="images/logo.png" alt="ViewVC logotype" /></a>
</td>
<td>
<h1>ViewVC Help: Log View</h1>
</td>
</tr>
<tr><td>
<h3>Help</h3>
<a href="help_rootview.html">General</a><br />
<a href="help_dirview.html">Directory&nbsp;View</a><br />
<strong>Log&nbsp;View</strong><br />
<a href="help_query.html">Query&nbsp;Database</a><br />
</td><td>
<h1>ViewVC Help: Log View</h1>
<h3>Internet</h3>
<a href="http://viewvc.org/index.html">Home</a><br />
<a href="http://viewvc.org/upgrading.html">Upgrading</a><br />
<a href="http://viewvc.org/contributing.html">Contributing</a><br />
<a href="http://viewvc.org/license-1.html">License</a><br />
</td><td colspan="2">
<p>
The log view displays the revision history of the selected source
file or directory. For each revision the following information is

View File

@@ -4,64 +4,59 @@
<head>
<title>ViewVC Help: Query The Commit Database</title>
<link rel="stylesheet" href="help.css" type="text/css" />
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<table>
<col class="menu" />
<col />
<tr>
<td><a href=".."><img
src="images/logo.png" alt="ViewVC logotype" /></a>
</td>
<td><h1>ViewVC Help: Query The Commit Database</h1></td>
</tr>
<tr><td>
<h3>Other&nbsp;Help:</h3>
<a href="help_rootview.html">General</a><br />
<a href="help_dirview.html">Directory&nbsp;View</a><br />
<a href="help_log.html">Classic&nbsp;Log&nbsp;View</a><br />
<a href="help_logtable.html">Alternative&nbsp;Log&nbsp;View</a><br />
<strong>Query&nbsp;Database</strong>
<h3>Internet</h3>
<a href="http://viewvc.org/index.html">Home</a><br />
<a href="http://viewvc.org/upgrading.html">Upgrading</a><br />
<a href="http://viewvc.org/contributing.html">Contributing</a><br />
<a href="http://viewvc.org/license-1.html">License</a><br />
</td><td colspan="2">
<p>
Select your parameters for querying the CVS commit database in the
form at the top of the page. You
can search for multiple matches by typing a comma-seperated list
into the text fields. Regular expressions, and wildcards are also
supported. Blank text input fields are treated as wildcards.
</p>
<p>
Any of the text entry fields can take a comma-seperated list of
search arguments. For example, to search for all commits from
authors <em>jpaint</em> and <em>gstein</em>, just type: <code>jpaint,
gstein</code> in the <em>Author</em> input box. If you are searching
for items containing spaces or quotes, you will need to quote your
request. For example, the same search above with quotes is:
<code>"jpaint", "gstein"</code>.
</p>
<p>
Wildcard and regular expression searches are entered in a similar
way to the quoted requests. You must quote any wildcard or
regular expression request, and a command character preceeds the
first quote. The command character <code>l</code>(lowercase L) is for wildcard
searches, and the wildcard character is a percent (<code>%</code>). The
command character for regular expressions is <code>r</code>, and is
passed directly to MySQL, so you'll need to refer to the MySQL
manual for the exact regex syntax. It is very similar to Perl. A
wildard search for all files with a <em>.py</em> extention is:
<code>l"%.py"</code> in the <em>File</em> input box. The same search done
with a regular expression is: <code>r".*\.py"</code>.
</p>
<p>
All search types can be mixed, as long as they are seperated by
commas.
</p>
</td></tr></table>
</body></html>
<div><a href="http://viewvc.org/index.html"><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
<table>
<col class="menu" />
<col />
<tr><td>
<h3>Help:</h3>
<a href="help_rootview.html">General</a><br />
<a href="help_dirview.html">Directory&nbsp;View</a><br />
<a href="help_log.html">Log&nbsp;View</a><br />
<strong>Query&nbsp;Database</strong>
</td><td>
<h1>ViewVC Help: Query The Commit Database</h1>
<p>
Select your parameters for querying the CVS commit database in the
form at the top of the page. You
can search for multiple matches by typing a comma-seperated list
into the text fields. Regular expressions, and wildcards are also
supported. Blank text input fields are treated as wildcards.
</p>
<p>
Any of the text entry fields can take a comma-seperated list of
search arguments. For example, to search for all commits from
authors <em>jpaint</em> and <em>gstein</em>, just type: <code>jpaint,
gstein</code> in the <em>Author</em> input box. If you are searching
for items containing spaces or quotes, you will need to quote your
request. For example, the same search above with quotes is:
<code>"jpaint", "gstein"</code>.
</p>
<p>
Wildcard and regular expression searches are entered in a similar
way to the quoted requests. You must quote any wildcard or
regular expression request, and a command character preceeds the
first quote. The command character <code>l</code>(lowercase L) is for wildcard
searches, and the wildcard character is a percent (<code>%</code>). The
command character for regular expressions is <code>r</code>, and is
passed directly to MySQL, so you'll need to refer to the MySQL
manual for the exact regex syntax. It is very similar to Perl. A
wildard search for all files with a <em>.py</em> extention is:
<code>l"%.py"</code> in the <em>File</em> input box. The same search done
with a regular expression is: <code>r".*\.py"</code>.
</p>
<p>
All search types can be mixed, as long as they are seperated by
commas.
</p>
</td></tr></table>
<hr />
<address><a href="mailto:users@viewvc.tigris.org">ViewVC Users Mailinglist</a></address>
</body>
</html>

View File

@@ -4,164 +4,152 @@
<head>
<title>ViewVC Help: General</title>
<link rel="stylesheet" href="help.css" type="text/css" />
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<div><a href="http://viewvc.org/index.html"><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
<table>
<col class="menu" />
<col />
<tr>
<td><a href=".."><img
src="images/logo.png" alt="ViewVC logotype" /></a>
</td>
<td>
<h1>ViewVC Help: General</h1>
</td>
</tr>
<tr><td>
<h3>Help</h3>
<strong>General</strong><br />
<a href="help_dirview.html">Directory&nbsp;View</a><br />
<a href="help_log.html">Log&nbsp;View</a><br />
<a href="help_query.html">Query&nbsp;Database</a><br />
</td><td>
<h3>Internet</h3>
<a href="http://viewvc.org/index.html">Home</a><br />
<a href="http://viewvc.org/upgrading.html">Upgrading</a><br />
<a href="http://viewvc.org/contributing.html">Contributing</a><br />
<a href="http://viewvc.org/license-1.html">License</a><br />
</td><td colspan="2">
<p><em>ViewVC</em> is a WWW interface for CVS and Subversion
repositories. It allows you to browse the files and directories in a
repository while showing you metadata from the repository history: log
messages, modification dates, author names, revision numbers, copy
history, and so on. It provides several different views of repository
data to help you find the information you are looking for:</p>
<ul>
<li><a name="view-dir" href="help_dirview.html"><strong>Directory
View</strong></a> - Shows a list of files and subdirectories in a
directory of the repository, along with metadata like author names and
log entries.</li>
<li><a name="view-log" href="help_log.html"><strong>Log
View</strong></a> - Shows a revision by revision list of all the
changes that have made to a file or directory in the repository, with
metadata and links to views of each revision.</li>
<li><a name="view-markup"><strong>File Contents View (Markup
View)</strong></a> - Shows the contents of a file at a particular
revision, with revision information at the top of the page. File
revisions which are GIF, PNG, or JPEG images are displayed inline on
the page. Other file types are displayed as marked up text. The markup
may be limited to turning URLs and email addresses into links, or
configured to show colorized source code.</li>
<li><a name="view-checkout"><strong>File Download (Checkout
View)</strong></a> - Retrieves the unaltered contents of a file
revision. Browsers may try to display the file, or just save it to
disk.</li>
<li><a name="view-annotate"><strong>File Annotate View</strong></a> -
Shows the contents of a file revision and breaks it down line by line,
showing the revision number where each one was last modified, along
with links and other information. <em>This view is disabled in some
ViewVC configurations</em></li>
<li><a name="view-diff"><strong>File Diff View</strong></a> - Shows
the changes made between two revisions of a file</li>
<li><a name="view-tarball"><strong>Directory Tarball View</strong> -
Retrieves a gzipped tar archive containing the contents of a
directory.<em>This view is disabled in the default ViewVC
configuration.</em></li>
<li><a name="view-query"><strong>Directory Query View</strong></a> -
Shows information about changes made to all subdirectories and files
under a parent directory, sorted and filtered by criteria you specify.
<em>This view is disabled in the default ViewVC configuration.</em>
</li>
<li><a name="view-rev"><strong>Revision View</strong> - Shows
information about a revision including log message, author, and a list
of changed paths. <em>For Subversion repositories only.</em></li>
<li><a name="view-graph"><strong>Graph View</strong></a> - Shows a
graphical representation of a file's revisions and branches complete
with tag and author names and links to markup and diff pages.
<em>For CVS repositories only, and disabled in the default
configuration.</em></li>
</ul>
<h3><a name="multiple-repositories">Multiple Repositories</a></h3>
<p>A single installation of ViewVC is often used to provide access to
more than one repository. In these installations, ViewVC shows a
<em>Project Root</em> drop down box in the top right corner of every
generated page to allow for quick access to any repository.</p>
<h3><a name="sticky-revision-tag">Sticky Revision and Tag</a></h3>
<p>By default, ViewVC will show the files and directories and revisions
that currently exist in the repository. But it's also possible to browse
the contents of a repository at a point in its past history by choosing
a "sticky tag" (in CVS) or a "sticky revision" (in Subversion) from the
forms at the top of directory and log pages. They're called sticky
because once they're chosen, they stick around when you navigate to
other pages, until you reset them. When they're set, directory and log
pages only show revisions preceding the specified point in history. In
CVS, when a tag refers to a branch or a revision on a branch, only
revisions from the branch history are shown, including branch points and
their preceding revisions.</p>
<h3><a name="dead-files">Dead Files</a></h3>
<p>In CVS directory listings, ViewVC can optionally display dead files.
Dead files are files which used to be in a directory but are currently
deleted, or files which just don't exist in the currently selected
<a href="#sticky-revision-tag">sticky tag</a>. Dead files cannot be
shown in Subversion repositories. The only way to see a deleted file in
a Subversion directory is to navigate to a sticky revision where the
file previously existed.</p>
<h3><a name="artificial-tags">Artificial Tags</a></h3>
<p>In CVS Repositories, ViewVC adds artificial tags <em>HEAD</em> and
<em>MAIN</em> to tag listings and accepts them in place of revision
numbers and real tag names in all URLs. <em>MAIN</em> acts like a branch
tag pointing at the default branch, while <em>HEAD</em> acts like a
revision tag pointing to the latest revision on the default branch. The
default branch is usually just the trunk, but may be set to other
branches inside individual repository files. CVS will always check out
revisions from a file's default branch when no other branch is specified
on the command line.</p>
<h3><a name="more-information">More Information</a></h3>
<p>More information about <em>ViewVC</em> is available from
<a href="http://viewvc.org/">viewvc.org</a>.
See the links below for guides to CVS and Subversion</p>
<h4>Documentation about CVS</h4>
<blockquote>
<p>
<a href="http://cvsbook.red-bean.com/"><em>Open Source
Development with CVS</em></a><br />
<a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html">CVS
User's Guide</a><br />
<a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html">Another CVS tutorial</a><br />
<a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/">Yet another CVS tutorial (a little old, but nice)</a><br />
<a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt">An old but very useful FAQ about CVS</a>
</p>
</blockquote>
<h4>Documentation about Subversion</h3>
<blockquote>
<p>
<a href="http://svnbook.red-bean.com/"><em>Version Control with
Subversion</em></a><br />
</p>
</blockquote>
<h1>ViewVC Help: General</h1>
<p><em>ViewVC</em> is a WWW interface for CVS and Subversion
repositories. It allows you to browse the files and directories in a
repository while showing you metadata from the repository history: log
messages, modification dates, author names, revision numbers, copy
history, and so on. It provides several different views of repository
data to help you find the information you are looking for:</p>
<ul>
<li><a name="multiple-repositories"><strong>Root Listing
View</strong></a> - Show a list of repositories configured for
display in ViewVC.</li>
<li><a name="view-dir" href="help_dirview.html"><strong>Directory
View</strong></a> - Shows a list of files and subdirectories in a
directory of the repository, along with metadata like author names and
log entries.</li>
<li><a name="view-log" href="help_log.html"><strong>Log
View</strong></a> - Shows a revision by revision list of all the
changes that have made to a file or directory in the repository, with
metadata and links to views of each revision.</li>
<li><a name="view-checkout"><strong>File Download (Checkout
View)</strong></a> - Retrieves the unaltered contents of a file
revision. Browsers may try to display the file, or just save it
to disk. <em>This view is disabled in the default ViewVC
configuration.</em></li>
<li><a name="view-annotate"><a name="view-markup"><strong>File
Contents View</strong></a></a> - Shows the contents of a file at
a particular revision, with revision information at the top of
the page. File revisions which are GIF, PNG, or JPEG images are
displayed inline on the page. Other file types are displayed as
marked up text. The markup may be limited to turning URLs and
email addresses into links, or configured to show colorized
source code. This view can optionally show line-based
annotation data for the file, containing the revision number
where each line was last modified, along with links and other
information. <em>This view is disabled in some ViewVC
configurations.</em></li>
<li><a name="view-diff"><strong>File Diff View</strong></a> - Shows
the changes made between two revisions of a file</li>
<li><a name="view-tarball"><strong>Directory Tarball View</strong> -
Retrieves a gzipped tar archive containing the contents of a
directory.<em>This view is disabled in the default ViewVC
configuration.</em></li>
<li><a name="view-query"><strong>Directory Query View</strong></a> -
Shows information about changes made to all subdirectories and files
under a parent directory, sorted and filtered by criteria you specify.
<em>This view is disabled in the default ViewVC configuration.</em>
</li>
<li><a name="view-rev"><strong>Revision View</strong> - Shows
information about a revision including log message, author, and a list
of changed paths. <em>For Subversion repositories only.</em></li>
<li><a name="view-graph"><strong>Graph View</strong></a> - Shows a
graphical representation of a file's revisions and branches complete
with tag and author names and links to markup and diff pages.
<em>For CVS repositories only, and disabled in the default
configuration.</em></li>
</ul>
<h3><a name="sticky-revision-tag">Sticky Revision and Tag</a></h3>
<p>By default, ViewVC will show the files and directories and revisions
that currently exist in the repository. But it's also possible to browse
the contents of a repository at a point in its past history by choosing
a "sticky tag" (in CVS) or a "sticky revision" (in Subversion) from the
forms at the top of directory and log pages. They're called sticky
because once they're chosen, they stick around when you navigate to
other pages, until you reset them. When they're set, directory and log
pages only show revisions preceding the specified point in history. In
CVS, when a tag refers to a branch or a revision on a branch, only
revisions from the branch history are shown, including branch points and
their preceding revisions.</p>
<h3><a name="dead-files">Dead Files</a></h3>
<p>In CVS directory listings, ViewVC can optionally display dead files.
Dead files are files which used to be in a directory but are currently
deleted, or files which just don't exist in the currently selected
<a href="#sticky-revision-tag">sticky tag</a>. Dead files cannot be
shown in Subversion repositories. The only way to see a deleted file in
a Subversion directory is to navigate to a sticky revision where the
file previously existed.</p>
<h3><a name="artificial-tags">Artificial Tags</a></h3>
<p>In CVS Repositories, ViewVC adds artificial tags <em>HEAD</em> and
<em>MAIN</em> to tag listings and accepts them in place of revision
numbers and real tag names in all URLs. <em>MAIN</em> acts like a branch
tag pointing at the default branch, while <em>HEAD</em> acts like a
revision tag pointing to the latest revision on the default branch. The
default branch is usually just the trunk, but may be set to other
branches inside individual repository files. CVS will always check out
revisions from a file's default branch when no other branch is specified
on the command line.</p>
<h3><a name="more-information">More Information</a></h3>
<p>More information about <em>ViewVC</em> is available from
<a href="http://viewvc.org/">viewvc.org</a>.
See the links below for guides to CVS and Subversion</p>
<h4>Documentation about CVS</h4>
<blockquote>
<p>
<a href="http://cvsbook.red-bean.com/"><em>Open Source
Development with CVS</em></a><br />
<a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html">CVS
User's Guide</a><br />
<a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html">Another CVS tutorial</a><br />
<a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/">Yet another CVS tutorial (a little old, but nice)</a><br />
<a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt">An old but very useful FAQ about CVS</a>
</p>
</blockquote>
<h4>Documentation about Subversion</h3>
<blockquote>
<p>
<a href="http://svnbook.red-bean.com/"><em>Version Control with
Subversion</em></a><br />
</p>
</blockquote>
</td></tr></table>
<hr />
<address><a href="mailto:users@viewvc.tigris.org">ViewVC Users Mailinglist</a></address>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -6,6 +6,7 @@
html, body {
color: #000000;
background-color: #ffffff;
font-family: sans-serif;
}
a:link { color: #0000ff; }
@@ -21,12 +22,36 @@ table {
table.auto {
width: auto;
}
table.fixed {
width: 100%;
table-layout: fixed;
}
table.fixed td {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
tr, td, th { vertical-align: top; }
th { white-space: nowrap; }
form { margin: 0; }
/** Navigation Headers ***/
/*** Icons ***/
.vc_icon {
width: 16px;
height: 16px;
border: none;
padding: 0 1px;
}
/*** Navigation Headers ***/
.vc_navheader {
background-color: #cccccc;
padding: .25em;
}
.vc_navheader .pathdiv {
padding: 0 3px;
}
@@ -47,7 +72,10 @@ form { margin: 0; }
background-color: #ffffff;
}
.vc_row_odd {
background-color: #ccccee;
background-color: #f0f0f0;
}
.vc_row_special {
background-color: #ffff7f;
}
@@ -62,44 +90,102 @@ form { margin: 0; }
}
/*** Markup Summary Header ***/
/*** Properties Listing ***/
.vc_properties {
margin: 1em 0;
}
/*** File Content Markup Styles ***/
.vc_summary {
background-color: #eeeeee;
}
/*** Highlight Markup Styles ***/
#vc_markup .num { color: #000000; }
#vc_markup .esc { color: #bd8d8b; }
#vc_markup .str { color: #bd8d8b; }
#vc_markup .dstr { color: #bd8d8b; }
#vc_markup .slc { color: #ac2020; font-style: italic; }
#vc_markup .com { color: #ac2020; font-style: italic; }
#vc_markup .dir { color: #000000; }
#vc_markup .sym { color: #000000; }
#vc_markup .line { color: #555555; }
#vc_markup .kwa { color: #9c20ee; font-weight: bold; }
#vc_markup .kwb { color: #208920; }
#vc_markup .kwc { color: #0000ff; }
#vc_markup .kwd { color: #404040; }
/*** Py2html Markup Styles ***/
#vc_markup .PY_STRING { color: #bd8d8b; }
#vc_markup .PY_COMMENT { color: #ac2020; font-style: italic; }
#vc_markup .PY_KEYWORD { color: #9c20ee; font-weight: bold; }
#vc_markup .PY_IDENTIFIER { color: #404040; }
/*** Line numbers outputted by highlight colorizer ***/
.line {
border-right-width: 1px;
#vc_file td {
border-right-style: solid;
border-right-color: #505050;
padding: 1px;
background-color: #eeeeee;
color: #505050;
text-decoration: none;
font-weight: normal;
font-style: normal;
padding: 1px 5px;
}
.vc_file_line_number {
border-right-width: 1px;
background-color: #eeeeee;
color: #505050;
text-align: right;
}
.vc_file_line_author, .vc_file_line_rev {
border-right-width: 1px;
text-align: right;
}
.vc_file_line_text {
border-right-width: 0px;
background-color: white;
font-family: monospace;
text-align: left;
white-space: pre;
width: 100%;
}
.pygments-c { color: #408080; font-style: italic } /* Comment */
.pygments-err { border: 1px solid #FF0000 } /* Error */
.pygments-k { color: #008000; font-weight: bold } /* Keyword */
.pygments-o { color: #666666 } /* Operator */
.pygments-cm { color: #408080; font-style: italic } /* Comment.Multiline */
.pygments-cp { color: #BC7A00 } /* Comment.Preproc */
.pygments-c1 { color: #408080; font-style: italic } /* Comment.Single */
.pygments-cs { color: #408080; font-style: italic } /* Comment.Special */
.pygments-gd { color: #A00000 } /* Generic.Deleted */
.pygments-ge { font-style: italic } /* Generic.Emph */
.pygments-gr { color: #FF0000 } /* Generic.Error */
.pygments-gh { color: #000080; font-weight: bold } /* Generic.Heading */
.pygments-gi { color: #00A000 } /* Generic.Inserted */
.pygments-go { color: #808080 } /* Generic.Output */
.pygments-gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.pygments-gs { font-weight: bold } /* Generic.Strong */
.pygments-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.pygments-gt { color: #0040D0 } /* Generic.Traceback */
.pygments-kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.pygments-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.pygments-kp { color: #008000 } /* Keyword.Pseudo */
.pygments-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.pygments-kt { color: #B00040 } /* Keyword.Type */
.pygments-m { color: #666666 } /* Literal.Number */
.pygments-s { color: #BA2121 } /* Literal.String */
.pygments-na { color: #7D9029 } /* Name.Attribute */
.pygments-nb { color: #008000 } /* Name.Builtin */
.pygments-nc { color: #0000FF; font-weight: bold } /* Name.Class */
.pygments-no { color: #880000 } /* Name.Constant */
.pygments-nd { color: #AA22FF } /* Name.Decorator */
.pygments-ni { color: #999999; font-weight: bold } /* Name.Entity */
.pygments-ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.pygments-nf { color: #0000FF } /* Name.Function */
.pygments-nl { color: #A0A000 } /* Name.Label */
.pygments-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.pygments-nt { color: #008000; font-weight: bold } /* Name.Tag */
.pygments-nv { color: #19177C } /* Name.Variable */
.pygments-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.pygments-w { color: #bbbbbb } /* Text.Whitespace */
.pygments-mf { color: #666666 } /* Literal.Number.Float */
.pygments-mh { color: #666666 } /* Literal.Number.Hex */
.pygments-mi { color: #666666 } /* Literal.Number.Integer */
.pygments-mo { color: #666666 } /* Literal.Number.Oct */
.pygments-sb { color: #BA2121 } /* Literal.String.Backtick */
.pygments-sc { color: #BA2121 } /* Literal.String.Char */
.pygments-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.pygments-s2 { color: #BA2121 } /* Literal.String.Double */
.pygments-se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.pygments-sh { color: #BA2121 } /* Literal.String.Heredoc */
.pygments-si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.pygments-sx { color: #008000 } /* Literal.String.Other */
.pygments-sr { color: #BB6688 } /* Literal.String.Regex */
.pygments-s1 { color: #BA2121 } /* Literal.String.Single */
.pygments-ss { color: #19177C } /* Literal.String.Symbol */
.pygments-bp { color: #008000 } /* Name.Builtin.Pseudo */
.pygments-vc { color: #19177C } /* Name.Variable.Class */
.pygments-vg { color: #19177C } /* Name.Variable.Global */
.pygments-vi { color: #19177C } /* Name.Variable.Instance */
.pygments-il { color: #666666 } /* Literal.Number.Integer.Long */
/*** Diff Styles ***/
.vc_diff_header {
@@ -140,13 +226,15 @@ form { margin: 0; }
font-family: sans-serif;
font-size: smaller;
}
.vc_diff_line_number {
}
.vc_raw_diff {
background-color: #cccccc;
font-size: smaller;
}
/*** Intraline Diff Styles ***/
/*** Intraline Diff Styles ***/
.vc_idiff_add {
background-color: #aaffaa;
}
@@ -159,7 +247,6 @@ form { margin: 0; }
.vc_idiff_empty {
background-color:#e0e0e0;
}
table.vc_idiff col.content {
width: 50%;
}
@@ -177,23 +264,19 @@ table.vc_idiff tbody th {
text-align:right;
}
/*** Annotate Styles ***/
.vc_blame_line, .vc_blame_author, .vc_blame_rev {
font-family: monospace;
font-size: smaller;
text-align: right;
white-space: nowrap;
padding-right: 1em;
}
.vc_blame_text {
font-family: monospace;
font-size: smaller;
text-align: left;
white-space: pre;
width: 100%;
}
/*** Query Form ***/
.vc_query_form {
background-color: #e6e6e6;
}
/*** Warning! ***/
.vc_warning {
border-width: 1px 2px 2px 2px;
border-color: black;
border-style: solid;
background-color: red;
color: white;
padding: 0.5em;
}

123
templates/file.ezt Normal file
View File

@@ -0,0 +1,123 @@
[# ------------------------------------------------------------------------- ]
[# CUSTOMIZE ME: To avoid displaying "binary garbage" -- the contents of ]
[# files with non-human-readable file formats -- change the value of the ]
[# hide_binary_garbage variable below to 1. ]
[# ------------------------------------------------------------------------- ]
[define hide_binary_garbage]0[end]
[# ------------------------------------------------------------------------- ]
[# setup page definitions]
[define page_title]Contents of /[where][end]
[define help_href][docroot]/help_rootview.html[end]
[# end]
[include "include/header.ezt" "markup"]
[include "include/file_header.ezt"]
<hr />
<div class="vc_summary">
Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong></a>[else]<strong>[rev]</strong>[end] -
([is annotation "annotated"]<a href="[view_href]"><strong>hide annotations</strong></a>[else]<a href="[annotate_href]"><strong>show annotations</strong></a>[end])
[if-any download_href](<a href="[download_href]"><strong>download</strong></a>)[end]
[if-any download_text_href](<a href="[download_text_href]"><strong>as text</strong></a>)[end]
[if-any vendor_branch] <em>(vendor branch)</em>[end]
<br /><em>[if-any date][date][else](unknown date)[end]</em>
[if-any ago]([ago] ago)[end]
by <em>[if-any author][author][else](unknown author)[end]</em>
[if-any orig_path]
<br />Original Path: <a href="[orig_href]"><em>[orig_path]</em></a>
[end]
[if-any branches]
<br />Branch: <strong>[branches]</strong>
[end]
[if-any tags]
<br />CVS Tags: <strong>[tags]</strong>
[end]
[if-any branch_points]
<br />Branch point for: <strong>[branch_points]</strong>
[end]
[is roottype "cvs"]
[if-any changed]
<br />Changes since <strong>[prev]: [changed] lines</strong>
[end]
[end]
[if-any mime_type]
<br />File MIME type: [mime_type]
[end]
[is roottype "svn"][if-any size]
<br />File size: [size] byte(s)
[end][end]
[if-any lockinfo]
<br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [lockinfo]
[end]
[is annotation "binary"]
<br /><strong>Unable to calculate annotation data on binary file contents.</strong>
[end]
[is annotation "error"]
<br /><strong>Error occurred while calculating annotation data.</strong>
[end]
[is state "dead"]
<br /><strong><em>FILE REMOVED</em></strong>
[end]
[if-any log]
<pre class="vc_log">[log]</pre>
[end]
</div>
[if-any prefer_markup][define hide_binary_garbage]0[end][end]
[if-any image_src_href][define hide_binary_garbage]0[end][end]
[is hide_binary_garbage "1"]
<p><strong>This file's contents are not viewable.
[if-any download_href]Please <a href="[download_href]">download</a>
this version of the file in order to view it.[end]</strong></p>
[else]
[define last_rev]0[end]
[define rowclass]vc_row_even[end]
[if-any lines]
<div id="vc_file">
<table cellspacing="0" cellpadding="0">
[for lines]
[is lines.rev last_rev]
[else]
[is lines.rev rev]
[define rowclass]vc_row_special[end]
[else]
[is rowclass "vc_row_even"]
[define rowclass]vc_row_odd[end]
[else]
[define rowclass]vc_row_even[end]
[end]
[end]
[end]
<tr class="[rowclass]" id="l[lines.line_number]">
<td class="vc_file_line_number">[lines.line_number]</td>
[is annotation "annotated"]
<td class="vc_file_line_author">[is lines.rev last_rev]&nbsp;[else][lines.author][end]</td>
<td class="vc_file_line_rev">[is lines.rev last_rev]&nbsp;[else][if-any lines.diff_href]<a href="[lines.diff_href]">[end][lines.rev][if-any lines.diff_href]</a>[end][end]</td>
[end]
<td class="vc_file_line_text">[lines.text]</td>
</tr>
[define last_rev][lines.rev][end]
[end]
</table>
</div>
[else]
[if-any image_src_href]
<div id="vc_file_image">
<img src="[image_src_href]" alt="" />
</div>
[end]
[end]
[end]
[include "include/props.ezt"]
[include "include/footer.ezt"]

View File

@@ -15,7 +15,7 @@
<tr>
<td>&nbsp;</td>
<td>
[diff_select_hidden_values]
[for diff_select_hidden_values]<input type="hidden" name="[diff_select_hidden_values.name]" value="[diff_select_hidden_values.value]"/>[end]
Diffs between
[if-any tags]
<select name="r1">
@@ -55,6 +55,7 @@
<select name="diff_format" onchange="submit()">
<option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
<option value="l" [is diff_format "l"]selected="selected"[end]>Long Colored Diff</option>
<option value="f" [is diff_format "f"]selected="selected"[end]>Full Colored Diff</option>
<option value="u" [is diff_format "u"]selected="selected"[end]>Unidiff</option>
<option value="c" [is diff_format "c"]selected="selected"[end]>Context Diff</option>
<option value="s" [is diff_format "s"]selected="selected"[end]>Side by Side</option>

View File

@@ -1,28 +1,9 @@
[if-any search_re_form]
<hr />
<div>
Show files containing the regular expression:
<form method="get" action="[search_re_action]" style="display: inline;">
<div style="display: inline;">
[search_re_hidden_values]
<input type="text" name="search" value="[search_re]" />
<input type="submit" value="Show" />
</div>
</form>
[if-any search_re]
<form method="get" action="[search_re_action]" style="display: inline;">
<div style="display: inline;">
[search_re_hidden_values]
<input type="submit" value="Show all files" />
</div>
</form>
[end]
[end]
</div>
[# if you want to disable tarball generation remove the following: ]
[if-any tarball_href]
<p style="margin:0;"><a href="[tarball_href]">Download GNU tarball</a></p>
<hr/>
<p style="margin:0;"><a href="[tarball_href]">Download GNU tarball</a></p>
[end]
[include "props.ezt"]
[include "footer.ezt"]

View File

@@ -24,15 +24,34 @@
[is roottype "svn"]
<tr>
<td>Directory revision:</td>
<td><a href="[tree_rev_href]">[tree_rev]</a>[if-any youngest_rev] (of <a href="[youngest_rev_href]">[youngest_rev]</a>)[end]</td>
<td><a href="[tree_rev_href]" title="Revision [tree_rev]">[tree_rev]</a>[if-any youngest_rev] (of <a href="[youngest_rev_href]" title="Revision [youngest_rev]">[youngest_rev]</a>)[end]</td>
</tr>
[end]
<tr>
<td>Sticky [is roottype "cvs"]Tag[else]Revision[end]:</td>
<td>[include "pathrev_form.ezt"]</td>
</tr>
[if-any search_re]
<tr><td>Current search:</td><td><strong>[search_re]</strong></td></tr>
[if-any search_re_action]
<tr>
<td>Filter files by content:</td>
<td><form method="get" action="[search_re_action]" style="display: inline;">
<div style="display: inline;">
[for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
<input type="text" name="search" value="[search_re]" />
<input type="submit" value="Search Regexp" />
</div>
</form>
[if-any search_re]
<form method="get" action="[search_re_action]" style="display: inline;">
<div style="display: inline;">
[for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
<input type="submit" value="Show All Files" />
</div>
</form>
[end]
</td>
</tr>
[end]
[if-any queryform_href]
@@ -41,24 +60,25 @@
<td><a href="[queryform_href]">Query revision history</a></td>
</tr>
[end]
</table>
[is cfg.options.use_pagesize "0"]
[is picklist_len "0"]
[else]
[is picklist_len "1"]
[else]
[is picklist_len "1"]
[else]
<form method="get" action="[dir_paging_action]">
[dir_paging_hidden_values]
<input type="submit" value="Go to:" />
<select name="dir_pagestart" onchange="submit()">
[for picklist]
<option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
[end]
</select>
</form>
[end]
<form method="get" action="[dir_paging_action]">
[for dir_paging_hidden_values]<input type="hidden" name="[dir_paging_hidden_values.name]" value="[dir_paging_hidden_values.value]"/>[end]
<input type="submit" value="Go to:" />
<select name="dir_pagestart" onchange="submit()">
[for picklist]
<option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
[end]
</select>
</form>
[end]
[end]
<p><a name="dirlist"></a></p>
<hr />

View File

@@ -1,16 +1,16 @@
<p style="margin:0;">
[is pathtype "file"]
<a href="[up_href]"><img src="[docroot]/images/back_small.png" width="16" height="16" alt="Parent Directory" /> Parent Directory</a>
<a href="[up_href]"><img src="[docroot]/images/back_small.png" class="vc_icon" alt="Parent Directory" /> Parent Directory</a>
[if-any log_href]
| <a href="[log_href][if-any log_href_rev]#rev[log_href_rev][end]"><img src="[docroot]/images/log.png" width="16" height="16" alt="Revision Log" /> Revision Log</a>
| <a href="[log_href]"><img src="[docroot]/images/log.png" class="vc_icon" alt="Revision Log" /> Revision Log</a>
[end]
[if-any graph_href]
| <a href="[graph_href]"><img src="[docroot]/images/cvsgraph_16x16.png" width="16" height="16" alt="View Revision Graph" /> Revision Graph</a>
| <a href="[graph_href]"><img src="[docroot]/images/cvsgraph_16x16.png" class="vc_icon" alt="View Revision Graph" /> Revision Graph</a>
[end]
[is view "diff"]
| <a href="[patch_href]"><img src="[docroot]/images/diff.png" width="16" height="16" alt="View Patch" /> Patch</a>
| <a href="[patch_href]"><img src="[docroot]/images/diff.png" class="vc_icon" alt="View Patch" /> Patch</a>
[end]
[else]
<a href="[view_href]"><img src="[docroot]/images/dir.png" width="16" height="16" alt="View Directory Listing" /> Directory Listing</a>
<a href="[view_href]"><img src="[docroot]/images/dir.png" class="vc_icon" alt="View Directory Listing" /> Directory Listing</a>
[end]
</p>

View File

@@ -4,12 +4,12 @@
<table>
<tr>
<td><address>[cfg.general.address]</address></td>
<td style="text-align: right;"><strong><a href="[help_href]">ViewVC Help</a></strong></td>
<td>[if-any cfg.general.address]<address><a href="mailto:[cfg.general.address]">[cfg.general.address]</a></address>[else]&nbsp;[end]</td>
<td style="text-align: right;">[if-any help_href]<strong><a href="[help_href]">ViewVC Help</a></strong>[else]&nbsp;[end]</td>
</tr>
<tr>
<td>Powered by <a href="http://viewvc.tigris.org/">ViewVC [vsn]</a></td>
<td style="text-align: right;">[if-any rss_href]<a href="[rss_href]" title="RSS 2.0 feed"><img src="[docroot]/images/feed-icon-16x16.jpg" alt="RSS 2.0 feed"/></a>[else]&nbsp;[end]</td>
<td style="text-align: right;">[if-any rss_href]<a href="[rss_href]" title="RSS 2.0 feed"><img src="[docroot]/images/feed-icon-16x16.jpg" class="vc_icon" alt="RSS 2.0 feed" /></a>[else]&nbsp;[end]</td>
</tr>
</table>

View File

@@ -5,71 +5,19 @@
<head>
<title>[if-any rootname][[][rootname]][else]ViewVC[end] [page_title]</title>
<meta name="generator" content="ViewVC [vsn]" />
<link rel="shortcut icon" href="[docroot]/images/favicon.ico" />
<link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
[if-any rss_href]<link rel="alternate" type="application/rss+xml" title="RSS [[][rootname]][where]" href="[rss_href]" />[end]
</head>
<body>
<div class="vc_navheader">
[if-any roots]
<form method="get" action="[change_root_action]">
[end]
<table style="padding:0.1em;">
<tr>
<td>
[if-any nav_path]<strong>
[for nav_path]
[if-any nav_path.href]<a href="[nav_path.href]">[end]
[if-index nav_path first]
[[][nav_path.name]][else]
[nav_path.name][end][if-any nav_path.href]</a>[end]
[if-index nav_path last][else]/[end]
[end]
</strong>
[end]
</td>
<td style="text-align:right;">
[if-any roots]
[change_root_hidden_values]
<strong>Repository:</strong>
<select name="root" onchange="submit()">
[define cvs_root_options][end]
[define svn_root_options][end]
<option value="*viewroots*"[is view "roots"] selected="selected"[else][end]>Repository Listing</option>
[for roots]
[define root_option][end]
[is roots.name rootname]
[define root_option]<option selected="selected">[roots.name]</option>[end]
[else]
[define root_option]<option>[roots.name]</option>[end]
[end]
[is roots.type "cvs"]
[define cvs_root_options][cvs_root_options][root_option][end]
[else]
[is roots.type "svn"]
[define svn_root_options][svn_root_options][root_option][end]
[end]
[end]
[end]
[is cvs_root_options ""][else]
<optgroup label="CVS Repositories">[cvs_root_options]</optgroup>
[end]
[is svn_root_options ""][else]
<optgroup label="Subversion Repositories">[svn_root_options]</optgroup>
[end]
</select>
<input type="submit" value="Go" />
[else]
&nbsp;
[end]
</td>
</tr>
</table>
[if-any roots]
</form>
[end]
<table><tr>
<td><strong>[if-any roots_href]<a href="[roots_href]"><span class="pathdiv">/</span></a>[else]<span class="pathdiv">/</span>[end][if-any nav_path][for nav_path][if-any nav_path.href]<a href="[nav_path.href]">[end][if-index nav_path first][[][nav_path.name]][else][nav_path.name][end][if-any nav_path.href]</a>[end][if-index nav_path last][else]<span class="pathdiv">/</span>[end][end][end]</strong></td>
<td style="text-align: right;">[if-any username]Logged in as: <strong>[username]</strong>[end]</td>
</tr></table>
</div>
<div style="float: right; padding: 5px;"><a href="http://www.viewvc.org/"><img src="[docroot]/images/logo.png" alt="ViewVC logotype" width="128" height="48" /></a></div>
<div style="float: right; padding: 5px;"><a href="http://www.viewvc.org/" title="ViewVC Home"><img src="[docroot]/images/viewvc-logo.png" alt="ViewVC logotype" width="240" height="70" /></a></div>
<h1>[page_title]</h1>

View File

@@ -19,14 +19,14 @@
[end]
[is pathtype "file"]
[if-any view_href]
[if-any head_view_href]
<tr>
<td>Links to HEAD:</td>
<td>
(<a href="[view_href]">view</a>)
[if-any download_href](<a href="[download_href]">download</a>)[end]
[if-any download_text_href](<a href="[download_text_href]">as text</a>)[end]
[if-any annotate_href](<a href="[annotate_href]">annotate</a>)[end]
(<a href="[head_view_href]">view</a>)
[if-any head_download_href](<a href="[head_download_href]">download</a>)[end]
[if-any head_download_text_href](<a href="[head_download_text_href]">as text</a>)[end]
[if-any head_annotate_href](<a href="[head_annotate_href]">annotate</a>)[end]
</td>
</tr>
[end]

View File

@@ -1,18 +1,20 @@
[is cfg.options.use_pagesize "0"]
[is picklist_len "0"]
[else]
[is picklist_len "1"]
[else]
<hr />
<form method="get" action="[log_paging_action]">
[log_paging_hidden_values]
[for log_paging_hidden_values]<input type="hidden" name="[log_paging_hidden_values.name]" value="[log_paging_hidden_values.value]"/>[end]
<input type="submit" value="Go to:">
<select name="log_pagestart" onchange="submit()">
[for picklist]
[if-any picklist.more]
<option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] ...</option>
[else]
<option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] - [picklist.end]</option>
[end]
[end]
</select>
</form>
[end]
[end]
[end]

View File

@@ -1,6 +1,6 @@
<form method="get" action="[pathrev_action]" style="display: inline">
<div style="display: inline">
[pathrev_hidden_values]
[for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
[is roottype "cvs"]
[define pathrev_selected][pathrev][end]
<select name="pathrev" onchange="submit()">
@@ -41,7 +41,7 @@
[if-any pathrev]
<form method="get" action="[pathrev_clear_action]" style="display: inline">
<div style="display: inline">
[pathrev_clear_hidden_values]
[for pathrev_clear_hidden_values]<input type="hidden" name="[pathrev_clear_hidden_values.name]" value="[pathrev_clear_hidden_values.value]"/>[end]
[if-any lastrev]
[is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]" />[end]
(<i>Current path doesn't exist after revision <strong>[lastrev]</strong></i>)

View File

@@ -0,0 +1,26 @@
[if-any properties]
<hr/>
<div class="vc_properties">
<h2>Properties</h2>
<table cellspacing="1" cellpadding="2" class="auto">
<thead>
<tr>
<th class="vc_header_sort">Name</th>
<th class="vc_header">Value</th>
</tr>
</thead>
<tbody>
[for properties]
<tr class="vc_row_[if-index properties even]even[else]odd[end]">
<td><strong>[properties.name]</strong></td>
[if-any properties.undisplayable]
<td><em>Property value is undisplayable.</em></td>
[else]
<td style="white-space: pre;">[properties.value]</td>
[end]
</tr>
[end]
</tbody>
</table>
</div>
[end]

View File

@@ -1,8 +1,10 @@
[is roottype "svn"]
[else]
<form method="get" action="[logsort_action]">
<div>
<hr />
<a name="logsort"></a>
[logsort_hidden_values]
[for logsort_hidden_values]<input type="hidden" name="[logsort_hidden_values.name]" value="[logsort_hidden_values.value]"/>[end]
Sort log by:
<select name="logsort" onchange="submit()">
<option value="cvs" [is logsort "cvs"]selected="selected"[end]>Not sorted</option>
@@ -12,3 +14,4 @@
<input type="submit" value=" Sort " />
</div>
</form>
[end]

View File

@@ -6,6 +6,7 @@
[for entries]
[if-index entries first][define first_revision][entries.rev][end][end]
[if-index entries last][define last_revision][entries.rev][end][end]
<div>
<hr />
@@ -19,10 +20,12 @@
[end]
Revision [is roottype "svn"]<a href="[entries.revision_href]"><strong>[entries.rev]</strong></a>[else]<strong>[entries.rev]</strong>[end] -
[is pathtype "file"]
(<a href="[entries.view_href]">view</a>)
[else]
<a href="[entries.view_href]">Directory Listing</a>
[if-any entries.view_href]
[is pathtype "file"]
(<a href="[entries.view_href]">view</a>)
[else]
<a href="[entries.view_href]">Directory Listing</a>
[end]
[end]
[if-any entries.download_href](<a href="[entries.download_href]">download</a>)[end]
[if-any entries.download_text_href](<a href="[entries.download_text_href]">as text</a>)[end]
@@ -48,7 +51,9 @@
[if-index entries last]Added[else]Modified[end]
[end]
<em>[entries.date]</em> ([entries.ago] ago) by <em>[entries.author]</em>
<em>[if-any entries.date][entries.date][else](unknown date)[end]</em>
[if-any entries.ago]([entries.ago] ago)[end]
by <em>[if-any entries.author][entries.author][else](unknown author)[end]</em>
[if-any entries.orig_path]
<br />Original Path: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a>
@@ -93,6 +98,10 @@
[end]
[end]
[if-any entries.lockinfo]
<br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]
[end]
[is entries.state "dead"]
<br /><strong><em>FILE REMOVED</em></strong>
[else]

View File

@@ -34,10 +34,12 @@
[# Tasks column]
<td>
[is pathtype "file"]
<a href="[entries.view_href]"><strong>View</strong></a><br />
[else]
<a href="[entries.view_href]"><strong>Directory Listing</strong></a><br />
[if-any entries.view_href]
[is pathtype "file"]
<a href="[entries.view_href]"><strong>View</strong></a><br />
[else]
<a href="[entries.view_href]"><strong>Directory Listing</strong></a><br />
[end]
[end]
[if-any entries.download_href]<a href="[entries.download_href]"><strong>Download</strong></a><br />[end]
[if-any entries.download_text_href]<a href="[entries.download_text_href]"><strong>As text</strong></a><br />[end]
@@ -108,7 +110,7 @@
[# Tags ]
[if-any entries.tags]
<form method=get action="[pathrev_action]" >
[pathrev_hidden_values]
[for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
<select name="pathrev" onChange="submit()">
<option value="" [is pathrev ""]selected[end]>Show all tags</option>
[for entries.tags]
@@ -126,7 +128,8 @@
[is roottype "svn"]
[if-index entries last]Added[else]Modified[end]
[end]
[entries.ago] ago<br /><em>[entries.date]</em>
[if-any entries.ago][entries.ago] ago<br />[end]
[if-any entries.date]<em>[entries.date]</em>[end]
[is roottype "cvs"]
[if-any entries.prev]
[if-any entries.changed]
@@ -144,9 +147,14 @@
</tr>
<tr class="vc_row_[if-index entries even]even[else]odd[end]">
<td colspan=5>
[if-any entries.lockinfo]
<strong>Lock status</strong>: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]<br />
[end]
[is roottype "svn"]
[if-any entries.orig_path]
Original Path: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a><br />
<strong>Original Path</strong>: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a><br />
[end]
[if-any entries.size]

View File

@@ -1,50 +0,0 @@
[# setup page definitions]
[define page_title]View of /[where][end]
[define help_href][docroot]/help_rootview.html[end]
[# end]
[include "include/header.ezt" "markup"]
[include "include/file_header.ezt"]
<hr />
<div class="vc_summary">
Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong></a>[else]<strong>[rev]</strong>[end] -
(<a href="[download_href]"><strong>download</strong></a>)
[if-any download_text_href](<a href="[download_text_href]"><strong>as text</strong></a>)[end]
[if-any annotate_href](<a href="[annotate_href]"><strong>annotate</strong></a>)[end]
[if-any vendor_branch] <em>(vendor branch)</em>[end]
<br />[if-any date]<em>[date]</em>[end]
[if-any ago]([ago] ago)[end]
[if-any author]by <em>[author]</em>[end]
[if-any orig_path]
<br />Original Path: <a href="[orig_href]"><em>[orig_path]</em></a>
[end]
[if-any branches]
<br />Branch: <strong>[branches]</strong>
[end]
[if-any tags]
<br />CVS Tags: <strong>[tags]</strong>
[end]
[if-any branch_points]
<br />Branch point for: <strong>[branch_points]</strong>
[end]
[is roottype "cvs"]
[if-any changed]
<br />Changes since <strong>[prev]: [changed] lines</strong>
[end]
[end]
[is roottype "svn"][if-any size]
<br />File size: [size] byte(s)
[end][end]
[is state "dead"]
<br /><strong><em>FILE REMOVED</em></strong>
[end]
[if-any log]
<pre class="vc_log">[log]</pre>
[end]
</div>
<div id="vc_markup"><pre>[markup]</pre></div>
[include "include/footer.ezt"]

View File

@@ -4,13 +4,13 @@
<!-- ViewVC :: http://www.viewvc.org/ -->
<head>
<title>Checkin Database Query</title>
<link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
[if-any docroot]<link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />[end]
</head>
<body>
[# setup page definitions]
[define help_href][docroot]/help_query.html[end]
[define help_href][if-any docroot][docroot]/help_query.html[end][end]
[# end]
<p>
@@ -158,7 +158,15 @@
[is query "skipped"]
[else]
<p><strong>[num_commits]</strong> matches found.</p>
[if-any row_limit_reached]
<p class="vc_warning">WARNING: These query results have been
artificially limited by an administrative threshold value and do
<em>not</em> represent the entirety of the data set which matches
the query. Consider modifying your query to be more specific</a>,
using your version control tool's query capabilities, or asking
your administrator to raise the database response size
threshold.</p>
[end]
[if-any commits]
<table cellspacing="0" cellpadding="2">
<thead>
@@ -202,21 +210,21 @@
</td>
[# uncommment, if you want a separate Description column:
{if-index commits.files first{
{if-index commits.files first}
<td style="vertical-align:top;" rowspan="{commits.num_files}">
{commits.log}
{if-any commits.log}{commits.log}{else}&nbsp;{end}
</td>
{end}
(substitute brackets for the braces)
]
</tr>
[# and also take the following out in the "Description column"-case:]
[# and also take the following out in the "Description column" case:]
[if-index commits.files last]
<tr class="vc_row_[if-index commits even]even[else]odd[end]">
<td>&nbsp;</td>
<td colspan="5"><strong>Log:</strong><br />
<pre class="vc_log">[commits.log]</pre></td>
<pre class="vc_log">[if-any commits.log][commits.log][else]&nbsp;[end]</pre></td>
</tr>
[end]
[# ---]

View File

@@ -6,13 +6,13 @@
[include "include/header.ezt" "query"]
<p><a href="[dir_href]">
<img src="[docroot]/images/dir.png" width="16" height="16" alt="Directory" />
<img src="[docroot]/images/dir.png" class="vc_icon" alt="Directory" />
Browse Directory</a></p>
<form action="[query_action]" method="get">
<div class="vc_query_form">
[query_hidden_values]
[for query_hidden_values]<input type="hidden" name="[query_hidden_values.name]" value="[query_hidden_values.value]"/>[end]
<table cellspacing="0" cellpadding="5" class="auto">
[is roottype "cvs"]
[# For subversion, the branch field is not used ]
@@ -102,6 +102,32 @@ Browse Directory</a></p>
</label>
</td>
</tr>
<tr>
<th style="text-align:right;vertical-align:top;">Comment:</th>
<td>
<input type="text" name="comment" value="[comment]" /><br />
<label for="comment_match_exact">
<input type="radio" name="comment_match" id="comment_match_exact"
value="exact" [is comment_match "exact"]checked=""[end] />
Exact match
</label>
<label for="comment_match_glob">
<input type="radio" name="comment_match" id="comment_match_glob"
value="glob" [is comment_match "glob"]checked=""[end] />
Glob pattern match
</label>
<label for="comment_match_regex">
<input type="radio" name="comment_match" id="comment_match_regex"
value="regex" [is comment_match "regex"]checked=""[end] />
Regex match
</label>
<label for="comment_match_notregex">
<input type="radio" name="comment_match" id="comment_match_notregex"
value="notregex" [is comment_match "notregex"]checked=""[end] />
Regex doesn't match
</label>
</td>
</tr>
<tr>
<th style="text-align:right;vertical-align:top;">Sort By:</th>
<td>

View File

@@ -7,6 +7,15 @@
<p><strong>[english_query]</strong></p>
[# <!-- {sql} --> ]
[if-any row_limit_reached]
<p class="vc_warning">WARNING: These query results have been
artificially limited by an administrative threshold value and do
<em>not</em> represent the entirety of the data set which matches
the query. Consider <a href="[queryform_href]">modifying your
query to be more specific</a>, using your version control tool's
query capabilities, or asking your administrator to raise the
database response size threshold.</p>
[end]
<p><a href="[queryform_href]">Modify query</a></p>
<p><a href="[backout_href]">Show commands which could be used to back out these changes</a></p>
@@ -34,7 +43,8 @@
<tbody>
<tr class="vc_row_[if-index commits even]even[else]odd[end]">
<td style="vertical-align: top;">
[if-any commits.files.rev]<a href="[if-any commits.files.prefer_markup][commits.files.view_href][else][commits.files.download_href][end]">[commits.files.rev]</a>[else]&nbsp;[end]
[define rev_href][if-any commits.files.prefer_markup][commits.files.view_href][else][if-any commits.files.download_href][commits.files.download_href][end][end][end]
[if-any commits.files.rev][if-any rev_href]<a href="[rev_href]">[end][commits.files.rev][if-any rev_href]</a>[end][else]&nbsp;[end]
</td>
<td style="vertical-align: top;">
<a href="[commits.files.dir_href]">[commits.files.dir]/</a>

View File

@@ -6,26 +6,33 @@
[include "include/header.ezt" "revision"]
<hr />
<form method="get" action="[jump_rev_action]">
<table cellspacing="1" cellpadding="2" style="width: auto;">
<tr align="left">
<th>Jump to revision:</th>
<td>
[jump_rev_hidden_values]
[for jump_rev_hidden_values]<input type="hidden" name="[jump_rev_hidden_values.name]" value="[jump_rev_hidden_values.value]"/>[end]
<input type="text" name="revision" value="[rev]" />
<input type="submit" value="Go" />
[if-any prev_href]
<a href="[prev_href]"><img src="[docroot]/images/back.png" alt="Previous" width="20" height="22" /></a>[end]
[if-any next_href] <a href="[next_href]"><img src="[docroot]/images/forward.png" width="20" height="22" alt="Next" /></a>[end]
<a href="[prev_href]" title="Previous Revision"><img src="[docroot]/images/back.png" alt="Previous" width="20" height="22" /></a>[end]
[if-any next_href] <a href="[next_href]" title="Next Revision"><img src="[docroot]/images/forward.png" width="20" height="22" alt="Next" /></a>[end]
</td>
</tr>
<tr align="left">
<th>Author:</th>
<td>[author]</td>
<td>[if-any author][author][else]<em>(unknown author)</em>[end]</td>
</tr>
<tr align="left">
<th>Date:</th>
<td>[date] <em>([ago] ago)</em></td>
<td>[if-any date][date][else]<em>(unknown date)</em>[end]
[if-any ago]<em>([ago] ago)</em>[end]</td>
</tr>
<tr align="left">
<th>Changed paths:</th>
<td><strong>[num_changes]</strong>
[if-any more_changes](showing only [limit_changes]; <a href="[more_changes_href]">show all</a>)[end][if-any first_changes](<a href="[first_changes_href]">show only first [first_changes]</a>)[end]</td>
</tr>
<tr align="left">
<th>Log Message:</th>
@@ -36,18 +43,7 @@
<hr />
<p><strong>Changed paths:</strong></p>
[if-any more_changes]
<div>
Only [limit_changes] changes shown,
<a href="[more_changes_href]">display [more_changes] more changes...</a>
</div>
[end]
[if-any first_changes]
<div><a href="[first_changes_href]">Show only first [first_changes] changes...</div>
[end]
<h2>Changed paths</h2>
<table cellspacing="1" cellpadding="2">
<thead>
@@ -60,11 +56,11 @@
[if-any changes]
[for changes]
<tr class="vc_row_[if-index changes even]even[else]odd[end]">
<td>[if-any changes.view_href]<a href="[changes.view_href]">[end]<img src="[docroot]/images/[is changes.pathtype "dir"]dir[else]text[end].png" width="16" height="16" alt="Directory" />[changes.path][is changes.pathtype "dir"]/[end][if-any changes.view_href]</a>[end]
<td>[if-any changes.view_href]<a href="[changes.view_href]" title="View [is changes.pathtype "dir"]Directory[else]File[end] Contents">[end]<img src="[docroot]/images/[is changes.pathtype "dir"]dir[else]text[end].png" class="vc_icon" alt="Directory" />[changes.path][is changes.pathtype "dir"]/[end][if-any changes.view_href]</a>[end]
[if-any changes.is_copy]<br /><em>(Copied from [changes.copy_path], r[changes.copy_rev])</em>[end]
</td>
<td>[if-any changes.log_href]<a href="[changes.log_href]">[end][changes.action][if-any changes.log_href]</a>[end]
[if-any changes.text_mods], [if-any changes.diff_href]<a href="[changes.diff_href]">[end]text changed[if-any changes.diff_href]</a>[end][end]
<td>[if-any changes.log_href]<a href="[changes.log_href]" title="View Log">[end][changes.action][if-any changes.log_href]</a>[end]
[if-any changes.text_mods], [if-any changes.diff_href]<a href="[changes.diff_href]" title="View Diff">[end]text changed[if-any changes.diff_href]</a>[end][end]
[if-any changes.prop_mods], props changed[end]
</td>
</tr>
@@ -74,7 +70,13 @@
<td colspan="5">No changed paths.</td>
</tr>
[end]
[if-any more_changes]
<tr>
<td colspan="5">[[]<a href="[more_changes_href]">...</a>]</td>
</tr>
[end]
</tbody>
</table>
[include "include/props.ezt"]
[include "include/footer.ezt"]

View File

@@ -9,6 +9,12 @@
<thead>
<tr>
<th class="vc_header_sort">Name</th>
[is cfg.options.show_roots_lastmod "1"]
<th class="vc_header">Revision</th>
<th class="vc_header">Age</th>
<th class="vc_header">Author</th>
<th class="vc_header">Log</th>
[end]
</tr>
</thead>
@@ -17,9 +23,15 @@
<tr class="vc_row_[if-index roots even]even[else]odd[end]">
<td>
<a href="[roots.href]">
<img src="[docroot]/images/dir.png" alt="" width="16" height="16" />
<img src="[docroot]/images/dir.png" alt="" class="vc_icon" />
[roots.name]</a>
</td>
[is cfg.options.show_roots_lastmod "1"]
<td style="width:20">&nbsp;[if-any roots.log_href]<a href="[roots.log_href]">[roots.rev]</a>[else][roots.rev][end]</td>
<td style="width:20">&nbsp;[roots.ago]</td>
<td style="width:20">&nbsp;[roots.author]</td>
<td style="width:20">&nbsp;[roots.short_log]</td>
[end]
</tr>
[end]
</tbody>

View File

@@ -1,16 +1,17 @@
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<link>[rss_link_href]</link>
<title>[rootname] checkins[if-any where] (in [where])[end]</title>
<description>[is roottype "svn"]Subversion[else]CVS[end] commits to the[if-any where] [where] directory of the[end] [rootname] repository</description>
[for commits]<item>
<title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [commits.short_log]</title>
<title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [format "xml"][commits.short_log][end]</title>
[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
<author>[commits.author]</author>
<pubDate>[if-any commits.rss_date][commits.rss_date][else](unknown date)[end]</pubDate>
<description>&lt;pre&gt;[format "xml"][commits.log][end]&lt;/pre&gt;</description>
<description>&#x3C;pre&#x3E;[format "xml"][format "html"][commits.log][end][end]&#x3C;/pre&#x3E;</description>
</item>[end]
</channel>
</rss>

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC

View File

@@ -1 +0,0 @@
build

0
tparse/Setup.py Normal file → Executable file
View File

Some files were not shown because too many files have changed in this diff Show More