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

Compare commits

..

49 Commits
1.0.0 ... 1.0.4

Author SHA1 Message Date
cmpilato
8b0bcade3b Tag the 1.0.4 final release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.0.4@1582 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 06:16:01 +00:00
cmpilato
3f09d2e039 Nail down a release date for 1.0.4.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1581 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 06:14:58 +00:00
cmpilato
ef501bd217 Backport from trunk r1579, whose log message read thusly:
(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/branches/1.0.x@1580 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 06:02:20 +00:00
cmpilato
e0342ff46e Backport from trunk r1486, whose lead message read thusly:
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/branches/1.0.x@1578 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 05:13:04 +00:00
cmpilato
d3210a1fec * templates/include/diff_form.ezt,
* templates/include/pathrev_form.ezt
  Fix various XHTML validation errors.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1576 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 05:01:22 +00:00
cmpilato
2ba682c141 * viewvc.conf.dist
(allow_tar): Move this to be closer to other allowed-view options.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1575 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-09 14:04:48 +00:00
cmpilato
6f67d8874a Backport from trunk r1573, whose log message read thusly:
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().

Also:

* CHANGES
  Note this fix.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1574 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-09 13:50:54 +00:00
cmpilato
88ef87c6af Backport to 1.0.x r1568 from trunk, which fixes some XHTML validation bugs.
* templates/include/footer.ezt,
* templates/include/header.ezt
  Fix the bugs ...

* CHANGES
  ... and note the fixes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1571 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-06 16:53:06 +00:00
cmpilato
dae7542569 Backport to 1.0.x r1569 from trunk, whose log message read thusly:
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.

Also:

* CHANGES
  Note this fix.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1570 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-06 16:48:25 +00:00
cmpilato
ea28160e45 * lib/viewvc.py
(redirect_pathrev): Automagically transform bogus input into,
    essentially, "HEAD".

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1567 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-04 03:07:46 +00:00
cmpilato
384d0dc1a6 * 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/branches/1.0.x@1565 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 19:37:07 +00:00
cmpilato
95927627b2 Backport from trunk r1561, which fixes bugs in viewvc-install's
ability to handle existing directories (and other filesystem errors)
on Windows.

* 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.

* CHANGES
  Note this fix.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1562 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 16:35:03 +00:00
cmpilato
d95ceab8a3 * lib/viewvc.py
Backport bugfix from trunk@r1559.

* CHANGES
  Note the change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1560 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 13:28:38 +00:00
cmpilato
1aff68d647 On the 1.0.x branch: backport from trunk r1557, which updates the URL
for the Python for Windows Extensions, and appends exception string
information which suggests they might be missing when failing to
import them.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1558 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 12:43:08 +00:00
cmpilato
4a3e55dac7 * INSTALL
(SECURITY INFORMATION): New section (copied from trunk).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1555 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-29 02:08:15 +00:00
cmpilato
171fadee27 * lib/viewvc.py
(view_markup): Raise an exception if the markup view is disable via
    runtime configuration

* CHANGES
  Note this fix.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1548 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-27 20:29:46 +00:00
cmpilato
bef839ab4e Backport to the 1.0.x branch r1344, which fixes a logic error that
broke EZT substitution pattern handling.

* lib/ezt.py
  (_write_value): Fix indentation / logic error.

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1541 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-16 05:06:58 +00:00
cmpilato
6647de80c3 Backport applicable portions of r1539 from trunk to the 1.0.x branch.
* lib/viewvc.py
  (_orig_path, 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/branches/1.0.x@1540 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-12 15:10:25 +00:00
cmpilato
99e1a51e20 Update the INSTALL file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1522 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-26 17:25:02 +00:00
cmpilato
c25dd8c213 * bin/loginfo-handler
Backport to the viewvc-1.0.x branch trunk revisions r1517 and r1518, which
  fix a buglet in the CVS 1.12 argument parsing and stdin consumption.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1519 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 19:54:33 +00:00
cmpilato
6cc6bde99f Backport to the viewvc-1.0.x branch the fix for issue #12, committed
in r1507 with the following log message:

   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.

Additionally:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1508 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 15:40:08 +00:00
cmpilato
d4c351e01f Backport to 1.0.x the fix for issue #262 (svndbadmin doesn't commit
data to MySQL InnoDB tables), committed to trunk in r1500.

* 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".

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1501 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-05 23:10:03 +00:00
cmpilato
7a5a7cfb69 Backport to viewvc-1.0.x the latest and greatest viewvc-install, which
brings the ability to be run from an arbitrary location, and vastly
improves the output.

* viewvc-install
  Bring into sync with trunk as of r1488.

* CHANGES
  Note these changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1489 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-20 18:14:51 +00:00
cmpilato
38b429220e Backport to the 1.0.x branch from trunk revisions 1345 and 1463:1465,
which fix issues 151 and 257, respectively.

Also:

* CHANGES
  Note these changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1466 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-02 04:00:47 +00:00
cmpilato
f42e157e88 Backport to 1.0.x r1456, whose log message ran thusly:
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.

Additionally:

 * CHANGES
   Add a change item to reflect this fix.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1457 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-18 01:18:14 +00:00
cmpilato
4312ecd3fa * CHANGES
Finalize 1.0.3 changes list.  Begin a new section for 1.0.4.

* lib/viewvc.py
  (__version__): Bump to 1.0.4-dev.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1448 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 20:31:49 +00:00
cmpilato
504ca48e0f Dictate UTF-8 as the output character set for all ViewVC template-driven
views.  

NOTE: This is a security-related fix.

* 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/branches/1.0.x@1446 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 20:18:34 +00:00
cmpilato
0c0ec82ca2 Merge r1443 and r1444 from trunk, which were follow-ups to the issue
#265 fix backported to the 1.0.x branch in r1441.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1445 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 20:01:02 +00:00
cmpilato
58a237b14c Backport to the 1.0.x branch r1440, whose log message read thusly:
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.

Additionally:

* CHANGES
  Create a new 1.0.3 section, and note the above change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1441 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 16:25:48 +00:00
cmpilato
24d1a691dc Update some branch files post-release.
* lib/viewvc.py
  (__version__): Bump for next release cycle.

* CHANGES
  Commit finalized date.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1435 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-09-29 16:56:51 +00:00
cmpilato
51011abec8 Backport to the 1.0.x branch r1428 from trunk, whose log message read
thusly:

   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

Additionally:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1429 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-09-28 01:13:36 +00:00
cmpilato
0bbe7f5751 Port r1422 to the 1.0.x branch.
* lib/viewvc.py
  (view_markup): Correct the syntax highlighter choosing logic.

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1423 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-16 16:32:09 +00:00
cmpilato
1df169ab24 Backport r1416 to the 1.0.x branch.
* 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.

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1419 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-01 18:17:39 +00:00
cmpilato
98e7612420 Backport fix for issue #245 (r1417) to the 1.0.x branch.
* 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.

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1418 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-01 18:15:32 +00:00
cmpilato
70b0076d88 Backport fix for issue #208 (r1414) to the 1.0.x branch.
* 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).

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1415 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-01 16:48:48 +00:00
cmpilato
e23b88d389 * CHANGES
Update with recent fixes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1398 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-21 09:51:27 +00:00
cmpilato
336ee6b95d Backport to the 1.0.x branch r1396, whose log message readly thusly:
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/branches/1.0.x@1397 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-21 09:51:13 +00:00
cmpilato
642130cf93 Merge the corrections to the INSTALL file made in r1386 to the 1.0.x branch.
Wish I'd remembered to do this *before* rolling 1.0.1...

* INSTALL
  Tweaky, tweaky...


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1395 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-21 09:40:36 +00:00
cmpilato
1e3c57f2e0 * lib/viewvc.py
(__version__): Bump to 1.0.2-dev.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1393 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-21 01:04:12 +00:00
cmpilato
9693f2b981 * CHANGES
Note recent change that uses real modification times for Subversion
  directories in generated tarballs.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1387 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-20 22:08:53 +00:00
cmpilato
69ab22922f Backport fix for issue #250 (r1384) to the 1.0.x branch.
* 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).

* CHANGES
  Note the change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1385 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 20:06:34 +00:00
cmpilato
d422c3abc9 Backport fix for issue #249 (r1382) to the 1.0.x branch.
* lib/query.py
  (main): Add 'rss_href' to the data dictionary so the template
    doesn't freak out.

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1383 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 18:35:29 +00:00
cmpilato
ded0015f5c Backport fix for issue #241 (r1377) to the 1.0.x branch.
* 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.

* CHANGES
  Update to reflect this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1378 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 15:53:09 +00:00
cmpilato
6232555f79 Backport fix for issue #237 (r1375) to the 1.0.x branch.
* lib/vclib/bincvs/__init__.py
  (_tag_tuple): Return () instead of raising a ValueError for
    single-slot revisions.

* CHANGES
  Update to reflect this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1376 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 15:31:44 +00:00
cmpilato
81fa4ce6fd Syncronize the 1.0.x CHANGES file with recent formatting fixes from trunk.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1369 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-26 15:49:25 +00:00
cmpilato
98378e7560 Backport the patch from r1367 (from issue #239), and not the change in
the CHANGES file.
   
* templates/include/footer.ezt
  Fix an XHTML validation error caused by not closing an <A> tag.

* CHANGES
  Note the bugfix.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1368 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-26 15:48:00 +00:00
cmpilato
8da2897df2 Backport r1357 to the 1.0.x release branch. That log message read:
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/branches/1.0.x@1361 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-18 17:31:55 +00:00
cmpilato
45bca25fbc * CHANGES
Add change for r1357's bugfix.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1359 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-18 17:27:57 +00:00
cmpilato
a54b3bcbbe * lib/viewvc.py
(__version__): Bump to 1.0.1-dev.

* CHANGES
  Give a date for the 1.0.0 release.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1352 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-01 21:20:24 +00:00
22 changed files with 1129 additions and 813 deletions

140
CHANGES
View File

@@ -1,56 +1,91 @@
Version 1.0 (1-May-2006)
Version 1.0.4 (released 10-Apr-2007)
* fix some markup bugs in query views (issue #266)
* fix loginfo-handler's support for CVS 1.12.9 (issues #151, #257)
* make viewvc-install able to run from an arbitrary location
* update viewvc-install's output for readability
* fix bug writing commits to non-MyISAM databases (issue #262)
* allow long paths in generated tarballs (issue #12)
* fix bug interpreting EZT substitute patterns
* fix broken markup view disablement
* fix broken directory view link generation in directory log view
* fix Windows-specific viewvc-install bugs
* fix broke query result links for Subversion deleted items (issue #296)
* fix some output XHTML validation buglets
* fix database query cache staleness problems (issue #180)
Version 1.0.3 (released 13-Oct-2006)
* fix bug in path shown for Subversion deleted-under-copy items (issue #265)
* security fix: declare charset for views to avoid IE UTF7 XSS attack
Version 1.0.2 (released 29-Sep-2006)
* minor documentation fixes
* fix Subversion annotate functionality on Windows (issue #18)
* fix annotate assertions on uncanonicalized #include paths (issue #208)
* make RSS URL method match the method used to generate it (issue #245)
* fix Subversion annotation to run non-interactively, preventing hangs
* fix bug in custom syntax highlighter fallback logic
* fix bug in PHP CGI hack to avoid force-cgi-redirect errors
Version 1.0.1 (released 20-Jul-2006)
* fix exception on log page when use_pagesize is enabled
* fix an XHTML validation bug in the footer template (issue #239)
* fix handling of single-component CVS revision numbers (issue #237)
* fix bug in download-as-text URL link generation (issue #241)
* fix query.cgi bug, missing 'rss_href' template data item (issue #249)
* no longer omit empty Subversion directories from tarballs (issue #250)
* use actual modification time for Subversion directories in tarballs
Version 1.0 (released 01-May-2006)
* add support for viewing Subversion repositories
* add support for running on MS Windows (2003-Feb-09)
* generate strict XHTML output (2005-Sep-08)
* add support for running on MS Windows
* generate strict XHTML output
* add support for caching by sending "Last-Modified", "Expires",
"ETag", and "Cache-Control" headers (2004-Jun-03)
"ETag", and "Cache-Control" headers
* add support for Mod_Python on Apache 2.x and ASP on IIS
* Several changes to standalone.py:
- -h commandline option to specify hostname for non local use.
- -r commandline option may be repeated to use more than repository
before actually installing ViewCVS.
- New GUI field to test paging.
* add new, better-integrated query interface (2004-Jul-17)
* add integrated RSS feeds (2005-Dec-22)
* add new, better-integrated query interface
* add integrated RSS feeds
* add new "root_as_url_component" option to embed root names as
path components in ViewCVS URLs for a more natural URL scheme
in ViewCVS configurations with multiple repositories.
(2002-Dec-12)
* add new "use_localtime" option to display local times instead of
UTC times (2002-May-06)
* add new "use_localtime" option to display local times instead of UTC times
* add new "root_parents" option to make it possible to add and
remove repositories without modifying the ViewCVS configuration
(2004-Jul-16)
* add new "template_dir" option to facilitate switching between
sets of templates (2005-Feb-08)
* add new "template_dir" option to facilitate switching between sets of
templates
* add new "sort_group_dirs" option to disable grouping of
directories in directory listings (2005-Mar-07)
* add new "port" option to connect to a MySQL database on a nonstandard
port (2005-Dec-22)
directories in directory listings
* add new "port" option to connect to a MySQL database on a nonstandard port
* make "default_root" option optional. When no root is specified,
show a page listing all available repositories (2005-Feb-04)
show a page listing all available repositories
* add "default_file_view" option to make it possible for relative
links and image paths in checked out HTML files to work without
the need for special /*checkout*/ prefixes in URLs. Deprecate
"checkout_magic" option and disable by default (2006-Apr-03)
* add "limit_changes" option to limit number of changed files shown
per commit by default in query results and in the Subversion revision
view (2005-Dec-23)
"checkout_magic" option and disable by default
* add "limit_changes" option to limit number of changed files shown per
commit by default in query results and in the Subversion revision view
* hide CVS "Attic" directories and add simple toggle for showing
dead files in directory listings (2004-Jul-31)
dead files in directory listings
* show Unified, Context and Side-by-side diffs in HTML instead of
in bare text pages (2004-Jun-22)
in bare text pages
* make View/Download links work the same for all file types
(2004-Jan-21)
* add links to tip of selected branch on log page (2005-Oct-03)
* allow use of "Highlight" program for colorizing (2005-Dec-20)
* add links to tip of selected branch on log page
* allow use of "Highlight" program for colorizing
* enable enscript colorizing for more file types
* add sorting arrows for directory views (2004-Jul-21)
* get rid of popup windows for checkout links (2004-Jan-21)
* add sorting arrows for directory views
* get rid of popup windows for checkout links
* obfuscate email addresses in html output by encoding @ symbol
with an HTML character reference (2004-Jul-29)
* add paging capability (2001-Dec-31)
with an HTML character reference
* add paging capability
* Improvements to templates
- add new template authoring guide
- increase coverage, use templates to produce HTML for diff pages,
@@ -59,43 +94,36 @@ Version 1.0 (1-May-2006)
- add new template variables providing ViewCVS URLs for more
links between related pages and less URL generation inside
templates
* add new [define] EZT directive for assigning variables within
templates (2004-Apr-21)
* add new [define] EZT directive for assigning variables within templates
* add command line argument parsing to install script to allow
non-interactive installs (2005-Jan-06)
* add stricter parameter validation to lower likelihood of CSS
vulnerabilities (2002-May-24)
non-interactive installs
* add stricter parameter validation to lower likelihood of cross-site
scripting vulnerabilities
* add support for cvsweb's "mime_type=text/x-cvsweb-markup" URLs
(2002-Oct-10)
* fix incompatibility with enscript 1.6.3 (2002-Feb-05)
* fix bug in parsing FreeBSD rlog output (2003-Jul-24)
* fix incompatibility with enscript 1.6.3
* fix bug in parsing FreeBSD rlog output
* work around rlog assumption all two digit years in RCS files are
relative to the year 1900. (2005-Sep-30)
relative to the year 1900.
* change loginfo-handler to cope with spaces in filenames and
support a simpler command line invocation from CVS (2003-Feb-11)
support a simpler command line invocation from CVS
* make cvsdbadmin work properly when invoked on CVS subdirectory
paths instead of top-level CVS root paths (2006-Mar-17)
* show diff error when comparing two binary files (2002-Jan-23)
* make regular expression search skip binary files (2002-Jan-17)
paths instead of top-level CVS root paths
* show diff error when comparing two binary files
* make regular expression search skip binary files
* make regular expression search skip nonversioned files in CVS
directories instead of choking on them (2002-Sep-27)
directories instead of choking on them
* fix tarball generator so it doesn't include forbidden modules
(2002-Feb-22)
* output "404 Not Found" errors instead of "403 Forbidden" errors
to not reveal whether forbidden paths exist (2005-May-17)
* fix sorting bug in directory view (2002-Apr-18)
to not reveal whether forbidden paths exist
* fix sorting bug in directory view
* reset log and directory page numbers when leaving those pages
(2005-Jan-29)
* reset sort direction in directory listing when clicking new
columns (2004-Jul-21)
* fix "Accept-Language" handling for Netscape 4.x browsers
(2002-May-23)
* fix file descriptor leak in standalone server (2004-Jul-17)
* clean up zombie processes from running enscript (2002-Jun-15)
* fix mysql "Too many connections" error in cvsdbadmin (2003-Jul-24)
* get rid of mxDateTime dependency for query database (2003-Feb-09)
* reset sort direction in directory listing when clicking new columns
* fix "Accept-Language" handling for Netscape 4.x browsers
* fix file descriptor leak in standalone server
* clean up zombie processes from running enscript
* fix mysql "Too many connections" error in cvsdbadmin
* get rid of mxDateTime dependency for query database
* store query database times in UTC instead of local time
(2003-Feb-09)
* fix daylight saving time bugs in various parts of the code
Version 0.9.4 (released 17-Aug-2005)

336
INSTALL
View File

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

View File

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

View File

@@ -39,7 +39,7 @@ CREATE TABLE branches (
branch varchar(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE branch (branch)
);
) TYPE=MyISAM;
DROP TABLE IF EXISTS checkins;
CREATE TABLE checkins (
@@ -62,7 +62,7 @@ CREATE TABLE checkins (
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid)
);
) TYPE=MyISAM;
DROP TABLE IF EXISTS descs;
CREATE TABLE descs (
@@ -71,7 +71,7 @@ CREATE TABLE descs (
hash bigint(20) DEFAULT '0' NOT NULL,
PRIMARY KEY (id),
KEY hash (hash)
);
) TYPE=MyISAM;
DROP TABLE IF EXISTS dirs;
CREATE TABLE dirs (
@@ -79,7 +79,7 @@ CREATE TABLE dirs (
dir varchar(255) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE dir (dir)
);
) TYPE=MyISAM;
DROP TABLE IF EXISTS files;
CREATE TABLE files (
@@ -87,7 +87,7 @@ CREATE TABLE files (
file varchar(255) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE file (file)
);
) TYPE=MyISAM;
DROP TABLE IF EXISTS people;
CREATE TABLE people (
@@ -95,7 +95,7 @@ CREATE TABLE people (
who varchar(32) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE who (who)
);
) TYPE=MyISAM;
DROP TABLE IF EXISTS repositories;
CREATE TABLE repositories (
@@ -103,7 +103,7 @@ CREATE TABLE repositories (
repository varchar(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE repository (repository)
);
) TYPE=MyISAM;
DROP TABLE IF EXISTS tags;
CREATE TABLE tags (
@@ -117,7 +117,7 @@ CREATE TABLE tags (
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid)
);
) TYPE=MyISAM;
"""
if __name__ == "__main__":

View File

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

View File

@@ -42,25 +42,28 @@ def link_includes(text, repos, path_parts, include_url):
match = re_includes.match(text)
if match:
incfile = match.group(3)
include_path_parts = path_parts[:-1]
for part in filter(None, string.split(incfile, '/')):
if part == "..":
if not include_path_parts:
# nothing left to pop; don't bother marking up this include.
return text
include_path_parts.pop()
elif part and part != ".":
include_path_parts.append(part)
# check current directory and parent directory for file
for depth in (-1, -2):
include_path = path_parts[:depth] + [incfile]
try:
# will throw if path doesn't exist
if repos.itemtype(include_path, None) == vclib.FILE:
break
except vclib.ItemNotFound:
pass
else:
include_path = None
include_path = None
try:
if repos.itemtype(include_path_parts, None) == vclib.FILE:
include_path = string.join(include_path_parts, '/')
except vclib.ItemNotFound:
pass
if include_path:
url = string.replace(include_url, '/WHERE/',
string.join(include_path, '/'))
return '#%sinclude%s<a href="%s">"%s"</a>' % \
(match.group(1), match.group(2), url, incfile)
return '#%sinclude%s<a href="%s">"%s"</a>' % \
(match.group(1), match.group(2),
string.replace(include_url, '/WHERE/', include_path), incfile)
return text

View File

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

View File

@@ -659,7 +659,7 @@ def _write_value(value, args, ctx):
piece = args[idx]
else:
piece = '<undef>'
printer(ctx, piece)
printer(ctx, piece)
# plain old value, write to output
else:

View File

@@ -403,6 +403,7 @@ def main(server, cfg, viewvc_link):
'query' : query,
'commits' : commits,
'num_commits' : len(commits),
'rss_href' : None,
}
if form_data.hours:

View File

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

View File

@@ -474,7 +474,7 @@ def _tag_tuple(revision_string):
t = map(int, string.split(revision_string, '.'))
l = len(t)
if l == 1:
raise ValueError
return ()
if l > 2 and t[-2] == 0 and l % 2 == 0:
del t[-2]
return tuple(t)

View File

@@ -270,62 +270,70 @@ class ChangedPath:
self.is_copy = is_copy
class ChangedPathSet:
def __init__(self):
self.changes = { }
def get_revision_info(svnrepos, rev):
fsroot = svnrepos._getroot(rev)
def add_change(self, change):
# 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)
path = change.path
action = 'modified'
is_copy = 0
if not change.path:
action = 'deleted'
path = change.base_path
elif change.added:
action = 'added'
replace_check_path = path
if change.base_path and change.base_rev:
is_copy = 1
replace_check_path = change.base_path
if self.changes.has_key(replace_check_path) \
and self.changes[replace_check_path].action == 'deleted':
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
self.changes[path] = ChangedPath(path, pathtype, change.prop_changes,
changedpaths[path] = ChangedPath(path, pathtype, change.prop_changes,
change.text_changed, change.base_path,
change.base_rev, action, is_copy)
def get_changes(self):
changes = self.changes.values()
changes.sort(lambda a, b: _compare_paths(a.filename, b.filename))
return changes
# Actually, what we want is a sorted list of ChangedPath objects.
change_items = changedpaths.values()
change_items.sort(lambda a, b: _compare_paths(a.filename, b.filename))
def get_revision_info(svnrepos, rev):
fsroot = svnrepos._getroot(rev)
# Get the changes for the revision
cps = ChangedPathSet()
editor = repos.ChangeCollector(svnrepos.fs_ptr, fsroot,
svnrepos.pool, cps.add_change)
e_ptr, e_baton = delta.make_editor(editor, svnrepos.pool)
repos.svn_repos_replay(fsroot, e_ptr, e_baton, svnrepos.pool)
# Now get the revision property info. Would use
# editor.get_root_props(), but something is broken there...
datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev, svnrepos.pool)
date = _datestr_to_date(datestr, svnrepos.pool)
return date, author, msg, cps.get_changes()
return date, author, msg, change_items
def _log_helper(svnrepos, rev, path, pool):
@@ -483,10 +491,18 @@ class BlameSource:
self.last = None
self.first_rev = first_rev
# Do a little dance to get a URL that works in both Unix-y and
# Windows worlds.
rootpath = os.path.abspath(rootpath)
if rootpath and rootpath[0] != '/':
rootpath = '/' + rootpath
if os.sep != '/':
rootpath = string.replace(rootpath, os.sep, '/')
url = 'file://' + string.join([rootpath, fs_path], "/")
fp = popen.popen(svn_client_path,
('blame', "-r%d" % int(rev), "%s@%d" % (url, int(rev))),
('blame', "-r%d" % int(rev), "--non-interactive",
"%s@%d" % (url, int(rev))),
'rb', 1)
self.fp = fp

View File

@@ -14,7 +14,7 @@
#
# -----------------------------------------------------------------------
__version__ = '1.0.0'
__version__ = '1.0.4'
# this comes from our library; measure the startup time
import debug
@@ -748,8 +748,11 @@ def _orig_path(request, rev_param='revision', path_param=None):
path = request.query_dict.get(path_param, request.where)
if rev is not None and hasattr(request.repos, '_getrev'):
pathrev = request.repos._getrev(request.pathrev)
rev = request.repos._getrev(rev)
try:
pathrev = request.repos._getrev(request.pathrev)
rev = request.repos._getrev(rev)
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
return _path_parts(vclib.svn.get_location(request.repos, path,
pathrev, rev)), rev
return _path_parts(path), rev
@@ -946,7 +949,7 @@ def get_file_view_info(request, where, rev=None, mime_type=None, pathrev=-1):
pathtype=vclib.FILE,
params={'content-type': 'text/plain',
'revision': rev,
'pathrev': rev},
'pathrev': pathrev},
escape=1)
if request.cfg.options.allow_annotate:
annotate_href = request.get_url(view_func=view_annotate,
@@ -1313,18 +1316,15 @@ def markup_stream_php(fp, cfg):
if not cfg.options.use_php:
return None
sys.stdout.flush()
# clearing the following environment variables prevents a
# "No input file specified" error from the php cgi executable
# when ViewVC is running under a cgi environment. when the
# php cli executable is used they can be left alone
#
#os.putenv("GATEWAY_INTERFACE", "")
#os.putenv("PATH_TRANSLATED", "")
#os.putenv("REQUEST_METHOD", "")
#os.putenv("SERVER_NAME", "")
#os.putenv("SERVER_SOFTWARE", "")
# The following HACK may be be used to allow a PHP CGI executable to be
# invoked instead of a CLI executable, on systems that do not have PHP's
# CLI (command line interface) installed. Just uncomment the following lines:
#os.unsetenv("SERVER_SOFTWARE")
#os.unsetenv("SERVER_NAME")
#os.unsetenv("GATEWAY_INTERFACE")
#os.unsetenv("REQUEST_METHOD")
#os.unsetenv("SCRIPT_FILENAME")
#os.unsetenv("PATH_TRANSLATED")
return MarkupPHP(cfg.options.php_exe_path, fp)
@@ -1359,6 +1359,10 @@ def make_rss_time_string(date, cfg):
return time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime(date)) + ' UTC'
def view_markup(request):
if not request.cfg.options.allow_markup:
raise debug.ViewVCException('Markup view is disabled',
'403 Forbidden')
cfg = request.cfg
path, rev = _orig_path(request)
fp, revision = request.repos.openfile(path, rev)
@@ -1425,14 +1429,17 @@ def view_markup(request):
streamer = markup_streamers.get(ext)
if streamer:
markup_fp = streamer(fp, cfg)
elif cfg.options.use_enscript:
markup_fp = MarkupEnscript(cfg, fp, request.path_parts[-1])
elif cfg.options.use_highlight:
markup_fp = MarkupHighlight(cfg, fp, request.path_parts[-1])
# If no one has a suitable markup handler, we'll use the default.
if not markup_fp:
markup_fp = MarkupPipeWrapper(fp)
# If there wasn't a custom streamer, or the streamer wasn't enabled, we'll
# try to use one of the configured syntax highlighting programs.
if not markup_fp:
if cfg.options.use_enscript:
markup_fp = MarkupEnscript(cfg, fp, request.path_parts[-1])
elif cfg.options.use_highlight:
markup_fp = MarkupHighlight(cfg, fp, request.path_parts[-1])
else:
# If no one has a suitable markup handler, we'll use the default.
markup_fp = MarkupPipeWrapper(fp)
data['markup'] = markup_fp
@@ -1514,7 +1521,10 @@ def view_directory(request):
# the directory listing (to take into account template changes or
# revision property changes).
if request.roottype == 'svn':
rev = request.repos._getrev(request.pathrev)
try:
rev = request.repos._getrev(request.pathrev)
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
tree_rev = vclib.svn.created_rev(request.repos, request.where, rev)
if check_freshness(request, None, str(tree_rev), weak=1):
return
@@ -1825,7 +1835,7 @@ def redirect_pathrev(request):
try:
new_pathrev = int(new_pathrev)
except ValueError:
pass
new_pathrev = youngest
except TypeError:
pass
else:
@@ -2090,9 +2100,8 @@ def view_log(request):
'tag_prefer_markup': prefer_markup,
})
else:
if not request.pathrev:
data['view_href'] = request.get_url(view_func=view_directory,
params={}, escape=1)
data['view_href'] = request.get_url(view_func=view_directory,
params={}, escape=1)
taginfo = options.get('cvs_tags', {})
tagitems = taginfo.items()
@@ -2123,7 +2132,7 @@ def view_log(request):
if cfg.options.use_pagesize:
data['log_pagestart'] = int(request.query_dict.get('log_pagestart',0))
data['entries'] = paging(data, 'entries', data['log_pagestart'],
'revision', cfg.options.use_pagesize)
'rev', cfg.options.use_pagesize)
request.server.header()
generate_page(request, "log", data)
@@ -2609,8 +2618,12 @@ def setup_diff(request):
sym2 = r2[idx+1:]
if request.roottype == 'svn':
rev1 = str(request.repos._getrev(rev1))
rev2 = str(request.repos._getrev(rev2))
try:
rev1 = str(request.repos._getrev(rev1))
rev2 = str(request.repos._getrev(rev2))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision(s) passed to diff',
'400 Bad Request')
p1 = _get_diff_path_parts(request, 'p1', rev1, request.pathrev)
p2 = _get_diff_path_parts(request, 'p2', rev2, request.pathrev)
@@ -2783,7 +2796,7 @@ def generate_tarball_header(out, name, size=0, mode=None, mtime=0,
uid=0, gid=0, typefrag=None, linkname='',
uname='viewvc', gname='viewvc',
devmajor=1, devminor=0, prefix=None,
magic='ustar', version='', chksum=None):
magic='ustar', version='00', chksum=None):
if not mode:
if name[-1:] == '/':
mode = 0755
@@ -2799,6 +2812,12 @@ def generate_tarball_header(out, name, size=0, mode=None, mtime=0,
if not prefix:
prefix = ''
# generate a GNU tar extension header for long names.
if len(name) >= 100:
generate_tarball_header(out, '././@LongLink', len(name), 0644, 0, 0, 0, 'L')
out.write(name)
out.write('\0' * (511 - ((len(name) + 511) % 512)))
block1 = struct.pack('100s 8s 8s 8s 12s 12s',
name,
'%07o' % mode,
@@ -2830,7 +2849,7 @@ def generate_tarball_header(out, name, size=0, mode=None, mtime=0,
out.write(block)
def generate_tarball(out, request, reldir, stack):
def generate_tarball(out, request, reldir, stack, dir_mtime=None):
# get directory info from repository
rep_path = request.path_parts + reldir
entries = request.repos.listdir(rep_path, request.pathrev, {})
@@ -2847,30 +2866,43 @@ def generate_tarball(out, request, reldir, stack):
if reldir:
tar_dir = tar_dir + _path_join(reldir) + '/'
# Subdirectory datestamps will be the youngest of the datestamps of
# version items (files for CVS, files or dirs for Subversion) in
# that subdirectory.
latest_date = 0
cvs = request.roottype == 'cvs'
for file in entries:
# Skip dead or busted CVS files, and CVS subdirs.
if (cvs and (file.kind != vclib.FILE or (file.rev is None or file.dead))):
continue
if file.date > latest_date:
latest_date = file.date
# If our caller doesn't dictate a datestamp to use for the current
# directory, its datestamps will be the youngest of the datestamps
# of versioned items in that subdirectory. We'll be ignoring dead
# or busted items and, in CVS, subdirs.
if dir_mtime is None:
dir_mtime = 0
for file in entries:
if cvs and (file.kind != vclib.FILE or file.rev is None or file.dead):
continue
if file.date > dir_mtime:
dir_mtime = file.date
# push directory onto stack. it will only be included in the tarball if
# files are found underneath it
# Push current directory onto the stack.
stack.append(tar_dir)
# If this is Subversion, we generate a header for this directory
# regardless of its contents. For CVS it will only get into the
# tarball if it has files underneath it, which we determine later.
if not cvs:
generate_tarball_header(out, tar_dir, mtime=dir_mtime)
# Run through the files in this directory, skipping busted ones.
for file in entries:
if (file.kind != vclib.FILE or
(cvs and (file.rev is None or file.dead))):
if file.kind != vclib.FILE:
continue
if cvs and (file.rev is None or file.dead):
continue
for dir in stack:
generate_tarball_header(out, dir, mtime=latest_date)
del stack[:]
# If we get here, we've seen at least one valid file in the
# current directory. For CVS, we need to make sure there are
# directory parents to contain it, so we flush the stack.
if cvs:
for dir in stack:
generate_tarball_header(out, dir, mtime=dir_mtime)
del stack[:]
if cvs:
info = os.stat(file.path)
@@ -2878,7 +2910,8 @@ def generate_tarball(out, request, reldir, stack):
else:
mode = 0644
### read the whole file into memory? bad... better to do 2 passes
### FIXME: Read the whole file into memory? Bad... better to do
### 2 passes.
fp = request.repos.openfile(rep_path + [file.name], request.pathrev)[0]
contents = fp.read()
fp.close()
@@ -2888,21 +2921,22 @@ def generate_tarball(out, request, reldir, stack):
out.write(contents)
out.write('\0' * (511 - ((len(contents) + 511) % 512)))
# recurse into subdirectories
# Recurse into subdirectories, skipping busted ones.
for file in entries:
if file.errors or file.kind != vclib.DIR:
continue
# skip forbidden/hidden directories (top-level only)
# Skip forbidden/hidden directories (top-level only).
if not rep_path:
if (request.cfg.is_forbidden(file.name)
or (cvs and request.cfg.options.hide_cvsroot
and file.name == 'CVSROOT')):
continue
generate_tarball(out, request, reldir + [file.name], stack)
mtime = request.roottype == 'svn' and file.date or None
generate_tarball(out, request, reldir + [file.name], stack, mtime)
# pop directory (if it's being pruned. otherwise stack is already empty)
# Pop the current directory from the stack.
del stack[-1:]
def download_tarball(request):
@@ -2916,6 +2950,8 @@ def download_tarball(request):
sys.stdout.flush()
fp = popen.pipe_cmds([('gzip', '-c', '-n')])
### FIXME: For Subversion repositories, we can get the real mtime of the
### top-level directory here.
generate_tarball(fp, request, [], [])
fp.write('\0' * 1024)
@@ -2928,7 +2964,11 @@ def view_revision(request):
data = common_template_data(request)
query_dict = request.query_dict
rev = request.repos._getrev(query_dict.get('revision'))
try:
rev = request.repos._getrev(query_dict.get('revision'))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
date, author, msg, changes = vclib.svn.get_revision_info(request.repos, rev)
date_str = make_time_string(date, request.cfg)
@@ -3129,22 +3169,23 @@ def english_query(request):
ret.append('subdirectories')
else:
ret.append('subdirectory')
ret.append(' <em>%s</em> ' % htmlify(dir))
ret.append(' <em>%s</em> ' % request.server.escape(dir))
file = request.query_dict.get('file', '')
if file:
if len(ret) != 1: ret.append('and ')
ret.append('to file <em>%s</em> ' % htmlify(file))
ret.append('to file <em>%s</em> ' % request.server.escape(file))
who = request.query_dict.get('who', '')
branch = request.query_dict.get('branch', '')
if branch:
ret.append('on branch <em>%s</em> ' % htmlify(branch))
ret.append('on branch <em>%s</em> ' % request.server.escape(branch))
else:
ret.append('on all branches ')
if who:
ret.append('by <em>%s</em> ' % htmlify(who))
ret.append('by <em>%s</em> ' % request.server.escape(who))
date = request.query_dict.get('date', 'hours')
if date == 'hours':
ret.append('in the last %s hours' % htmlify(request.query_dict.get('hours', '2')))
ret.append('in the last %s hours' \
% request.server.escape(request.query_dict.get('hours', '2')))
elif date == 'day':
ret.append('in the last day')
elif date == 'week':
@@ -3184,12 +3225,13 @@ def build_commit(request, files, limited_files, dir_strip):
desc = files[0].GetDescription()
commit.log = htmlify(desc)
commit.short_log = format_log(desc, request.cfg)
commit.author = htmlify(files[0].GetAuthor())
commit.author = request.server.escape(files[0].GetAuthor())
commit.rss_date = make_rss_time_string(files[0].GetTime(), request.cfg)
if request.roottype == 'svn':
commit.rev = files[0].GetRevision()
commit.rss_url = 'http://%s%s' % \
(request.server.getenv("HTTP_HOST"),
commit.rss_url = '%s://%s%s' % \
(request.server.getenv("HTTPS") == "on" and "https" or "http",
request.server.getenv("HTTP_HOST"),
request.get_url(view_func=view_revision,
params={'revision': commit.rev},
escape=1))
@@ -3205,7 +3247,10 @@ def build_commit(request, files, limited_files, dir_strip):
commit_time = make_time_string(commit_time, request.cfg)
else:
commit_time = '&nbsp;'
change_type = f.GetTypeString()
rev = f.GetRevision()
rev_prev = prev_rev(rev)
dirname = f.GetDirectory()
filename = f.GetFile()
if dir_strip:
@@ -3214,30 +3259,41 @@ def build_commit(request, files, limited_files, dir_strip):
dirname = dirname[len_strip+1:]
filename = dirname and ("%s/%s" % (dirname, filename)) or filename
params = { 'revision': f.GetRevision() }
if f.GetBranch(): params['pathrev'] = f.GetBranch()
# In CVS, we can actually look at deleted revisions; in Subversion
# we can't -- we'll look at the previous revision instead.
if request.roottype == 'svn':
if change_type == 'Remove':
params = { 'pathrev': rev_prev }
else:
params = { 'pathrev': rev }
else:
params = { 'revision': rev, 'pathrev': f.GetBranch() or None }
dir_href = request.get_url(view_func=view_directory,
where=dirname, pathtype=vclib.DIR,
params=params,
escape=1)
params=params, escape=1)
log_href = request.get_url(view_func=view_log,
where=filename, pathtype=vclib.FILE,
params=params,
escape=1)
params=params, escape=1)
diff_href = view_href = download_href = None
view_href = request.get_url(view_func=view_markup,
where=filename, pathtype=vclib.FILE,
params={'revision': f.GetRevision() },
escape=1)
where=filename, pathtype=vclib.FILE,
params=params, escape=1)
download_href = request.get_url(view_func=view_checkout,
where=filename, pathtype=vclib.FILE,
params={'revision': f.GetRevision() },
escape=1)
diff_href = request.get_url(view_func=view_diff,
where=filename, pathtype=vclib.FILE,
params={'r1': prev_rev(f.GetRevision()),
'r2': f.GetRevision(),
'diff_format': None},
escape=1)
params=params, escape=1)
if change_type == 'Change':
diff_href_params = params.copy()
diff_href_params.update({
'r1': rev_prev,
'r2': rev,
'diff_format': None
})
diff_href = request.get_url(view_func=view_diff,
where=filename, pathtype=vclib.FILE,
params=diff_href_params, escape=1)
prefer_markup = ezt.boolean(default_view(guess_mime(filename),
request.cfg) == view_markup)
# skip files in forbidden or hidden modules
dir_parts = filter(None, string.split(dirname, '/'))
@@ -3248,21 +3304,19 @@ def build_commit(request, files, limited_files, dir_strip):
continue
commit.files.append(_item(date=commit_time,
dir=htmlify(dirname),
file=htmlify(f.GetFile()),
author=htmlify(f.GetAuthor()),
rev=f.GetRevision(),
dir=request.server.escape(dirname),
file=request.server.escape(f.GetFile()),
author=request.server.escape(f.GetAuthor()),
rev=rev,
branch=f.GetBranch(),
plus=int(f.GetPlusCount()),
minus=int(f.GetMinusCount()),
type=f.GetTypeString(),
type=change_type,
dir_href=dir_href,
log_href=log_href,
view_href=view_href,
download_href=download_href,
prefer_markup=ezt.boolean
(default_view(guess_mime(filename), request.cfg)
== view_markup),
prefer_markup=prefer_markup,
diff_href=diff_href))
return commit
@@ -3384,7 +3438,7 @@ def view_query(request):
# run the query
db.RunQuery(query)
sql = htmlify(db.CreateSQLQueryString(query))
sql = request.server.escape(db.CreateSQLQueryString(query))
# gather commits
commits = []

View File

@@ -15,8 +15,18 @@
# -----------------------------------------------------------------------
import os, sys, traceback, string, thread
try:
import win32api
except ImportError, e:
raise ImportError, str(e) + """
Did you install the Python for Windows Extensions?
http://sourceforge.net/projects/pywin32/
"""
import win32process, win32pipe, win32con
import win32event, win32file, win32api, winerror
import win32event, win32file, winerror
import pywintypes, msvcrt
# Buffer size for spooling

View File

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

View File

@@ -32,7 +32,7 @@
[# if you want to disable tarball generation remove the following: ]
[if-any tarball_href]
<p style="margin:0;"><a href="[tarball_href]">Download tarball</a></p>
<p style="margin:0;"><a href="[tarball_href]">Download GNU tarball</a></p>
[end]
[include "footer.ezt"]

View File

@@ -5,11 +5,11 @@
<table>
<tr>
<td><address>[cfg.general.address]</address></td>
<td style="text-align: right;"><strong><a href="[help_href]">ViewVC Help</strong></td>
<td style="text-align: right;"><strong><a href="[help_href]">ViewVC Help</a></strong></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"/>[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" alt="RSS 2.0 feed"/></a>[else]&nbsp;[end]</td>
</tr>
</table>

View File

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

View File

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

View File

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

View File

@@ -359,6 +359,9 @@ hr_ignore_keyword_subst = 1
#
hr_intraline = 0
# allow on-the-fly generation of repository tarballs
allow_tar = 0
# allow annotation of files.
allow_annotate = 1
@@ -459,16 +462,14 @@ highlight_convert_tabs = 2
use_php = 0
# path to php executable
# (This should be set to the path of a PHP CLI executable, not the path
# to a CGI executable. If you use a CGI executable, you may see "no input file
# specified" or "force-cgi-redirect" errors instead of colorized source. The
# output of "php -v" tells you whether an given executable is CLI or CGI.)
php_exe_path = php
# php_exe_path = /usr/local/bin/php
# php_exe_path = C:\Program Files\php\cli\php.exe
#
# ViewVC can generate tarball from a repository on the fly.
#
allow_tar = 0
# allow_tar = 1
#
# Use CvsGraph. See http://www.akhphd.au.dk/~bertho/cvsgraph/ for
# documentation and download.

View File

@@ -14,7 +14,7 @@ ViewVC requires the Python interpreter which you can download from
and the Python for Windows Extensions which are at
http://starship.python.net/crew/mhammond/win32/
http://sourceforge.net/projects/pywin32/
For CVS support, ViewVC also requires that the CVSNT client (cvs.exe) OR the
RCS tools (rlog.exe, rcsdiff.exe, and co.exe) be installed on your computer.
@@ -404,7 +404,7 @@ KNOWN ISSUES
page would always return nothing (leaving the screen blank). There were a
number of workarounds for this problem, but the fix is to download and
install the latest python win32 extensions from
http://starship.python.net/crew/mhammond/win32/Downloads.html
http://sourceforge.net/projects/pywin32/
- ViewVC can't convert timestamps on diff pages to local time when it is used
with CVSNT. This is caused by a CVSNT bug, which is described at