mirror of
https://github.com/vitalif/viewvc-4intranet
synced 2019-04-16 04:14:59 +03:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8b0bcade3b |
63
CHANGES
63
CHANGES
@@ -1,66 +1,3 @@
|
|||||||
Version 1.0.13 (released 24-Oct-2012)
|
|
||||||
|
|
||||||
* security fix: escape "extra" diff info to avoid XSS attack (issue #515)
|
|
||||||
* security fix: remove user-reachable override of cvsdb row limit
|
|
||||||
* fix obscure "unexpected NULL parent pool" Subversion bindings error
|
|
||||||
* fix svndbadmin failure on deleted paths under Subversion 1.7 (issue #499)
|
|
||||||
|
|
||||||
Version 1.0.12 (released 02-Jun-2010)
|
|
||||||
|
|
||||||
* fix exception caused by trying to HTML-escape non-string data (issue #454)
|
|
||||||
|
|
||||||
Version 1.0.11 (released 29-Mar-2010)
|
|
||||||
|
|
||||||
* security fix: escape user-provided search_re input to avoid XSS attack
|
|
||||||
|
|
||||||
Version 1.0.10 (released 10-Mar-2010)
|
|
||||||
|
|
||||||
* security fix: escape user-provided query form input to avoid XSS attack
|
|
||||||
* fix errors viewing remote Subversion paths with URI-unsafe characters
|
|
||||||
* fix regexp input validation (issue #426, #427, #440)
|
|
||||||
|
|
||||||
Version 1.0.9 (released 11-Aug-2009)
|
|
||||||
|
|
||||||
* security fix: validate the 'view' parameter to avoid XSS attack
|
|
||||||
* security fix: avoid printing illegal parameter names and values
|
|
||||||
|
|
||||||
Version 1.0.8 (released 05-May-2009)
|
|
||||||
|
|
||||||
* fix directory view sorting UI
|
|
||||||
* tolerate malformed Accept-Language headers (issue #396)
|
|
||||||
* fix directory log views in revision-less Subversion repositories
|
|
||||||
* fix exception in rev-sorted remote Subversion directory views (issue #409)
|
|
||||||
|
|
||||||
Version 1.0.7 (released 14-Oct-2008)
|
|
||||||
|
|
||||||
* fix regression in the 'as text' download view (issue #373)
|
|
||||||
|
|
||||||
Version 1.0.6 (released 16-Sep-2008)
|
|
||||||
|
|
||||||
* security fix: ignore arbitrary user-provided MIME types (issue #354)
|
|
||||||
* fix bug in regexp search filter when used with sticky tag (issue #346)
|
|
||||||
* fix bug in handling of certain 'co' output (issue #348)
|
|
||||||
* fix regexp search filter template bug
|
|
||||||
* fix annotate code syntax error
|
|
||||||
* fix mod_python import cycle (issue #369)
|
|
||||||
|
|
||||||
Version 1.0.5 (released 28-Feb-2008)
|
|
||||||
|
|
||||||
* security fix: omit commits of all-forbidden files from query results
|
|
||||||
* security fix: disallow direct URL navigation to hidden CVSROOT folder
|
|
||||||
* security fix: strip forbidden paths from revision view
|
|
||||||
* security fix: don't traverse log history thru forbidden locations
|
|
||||||
* security fix: honor forbiddenness via diff view path parameters
|
|
||||||
* new 'forbiddenre' regexp-based path authorization feature
|
|
||||||
* fix root name conflict resolution inconsistencies (issue #287)
|
|
||||||
* fix an oversight in the CVS 1.12.9 loginfo-handler support
|
|
||||||
* fix RSS feed content type to be more specific (issue #306)
|
|
||||||
* fix entity escaping problems in RSS feed data (issue #238)
|
|
||||||
* fix bug in tarball generation for remote Subversion repositories
|
|
||||||
* fix query interface file-count-limiting logic
|
|
||||||
* fix query results plus/minus count to ignore forbidden files
|
|
||||||
* fix blame error caused by 'svn' unable to create runtime config dir
|
|
||||||
|
|
||||||
Version 1.0.4 (released 10-Apr-2007)
|
Version 1.0.4 (released 10-Apr-2007)
|
||||||
|
|
||||||
* fix some markup bugs in query views (issue #266)
|
* fix some markup bugs in query views (issue #266)
|
||||||
|
12
INSTALL
12
INSTALL
@@ -34,7 +34,7 @@ Congratulations on getting this far. :-)
|
|||||||
(http://www.python.org/)
|
(http://www.python.org/)
|
||||||
* Subversion, Version Control System, 1.2.0 or later
|
* Subversion, Version Control System, 1.2.0 or later
|
||||||
(binary installation and Python bindings)
|
(binary installation and Python bindings)
|
||||||
(http://subversion.apache.org/)
|
(http://subversion.tigris.org/)
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
|
|
||||||
@@ -260,16 +260,6 @@ or if you've got Mod_Python installed you can use METHOD D:
|
|||||||
http://<server_name>/viewvc/~checkout~/<module_name>
|
http://<server_name>/viewvc/~checkout~/<module_name>
|
||||||
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
|
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
|
||||||
|
|
||||||
5) Optional: Protect your ViewVC instance from server-whacking webcrawlers.
|
|
||||||
|
|
||||||
As ViewVC is a web-based application which each page containing various
|
|
||||||
links to other pages and views, you can expect your server's performance
|
|
||||||
to suffer if a webcrawler finds your ViewVC instance and begins
|
|
||||||
traversing those links. We highly recommend that you add your ViewVC
|
|
||||||
location to a site-wide robots.txt file. Visit the Wikipedia page
|
|
||||||
for Robots.txt (http://en.wikipedia.org/wiki/Robots.txt) for more
|
|
||||||
information.
|
|
||||||
|
|
||||||
|
|
||||||
UPGRADING VIEWVC
|
UPGRADING VIEWVC
|
||||||
-----------------
|
-----------------
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -77,8 +77,6 @@ def Cvs1Dot12ArgParse(args):
|
|||||||
|
|
||||||
if args[1] == '- New directory':
|
if args[1] == '- New directory':
|
||||||
return None, None
|
return None, None
|
||||||
elif args[1] == '- Imported sources':
|
|
||||||
return None, None
|
|
||||||
else:
|
else:
|
||||||
directory = args.pop(0)
|
directory = args.pop(0)
|
||||||
files = []
|
files = []
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -42,23 +42,9 @@ if LIBRARY_DIR:
|
|||||||
sys.path.insert(0, LIBRARY_DIR)
|
sys.path.insert(0, LIBRARY_DIR)
|
||||||
|
|
||||||
import sapi
|
import sapi
|
||||||
import imp
|
import viewvc
|
||||||
|
import query
|
||||||
# Import real ViewVC module
|
reload(query) # need reload because initial import loads this stub file
|
||||||
fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
|
|
||||||
try:
|
|
||||||
viewvc = imp.load_module('viewvc', fp, pathname, description)
|
|
||||||
finally:
|
|
||||||
if fp:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
# Import real ViewVC Query modules
|
|
||||||
fp, pathname, description = imp.find_module('query', [LIBRARY_DIR])
|
|
||||||
try:
|
|
||||||
query = imp.load_module('query', fp, pathname, description)
|
|
||||||
finally:
|
|
||||||
if fp:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
cfg = viewvc.load_config(CONF_PATHNAME)
|
cfg = viewvc.load_config(CONF_PATHNAME)
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -42,15 +42,9 @@ if LIBRARY_DIR:
|
|||||||
sys.path.insert(0, LIBRARY_DIR)
|
sys.path.insert(0, LIBRARY_DIR)
|
||||||
|
|
||||||
import sapi
|
import sapi
|
||||||
import imp
|
import viewvc
|
||||||
|
reload(viewvc) # need reload because initial import loads this stub file
|
||||||
|
|
||||||
# Import real ViewVC module
|
|
||||||
fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
|
|
||||||
try:
|
|
||||||
viewvc = imp.load_module('viewvc', fp, pathname, description)
|
|
||||||
finally:
|
|
||||||
if fp:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
def index(req):
|
def index(req):
|
||||||
server = sapi.ModPythonServer(req)
|
server = sapi.ModPythonServer(req)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
|
||||||
# Copyright (C) 2004 James Henstridge
|
# Copyright (C) 2004 James Henstridge
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
@@ -155,7 +154,7 @@ class SvnRev:
|
|||||||
fsroot = self._get_root_for_rev(rev)
|
fsroot = self._get_root_for_rev(rev)
|
||||||
|
|
||||||
# find changes in the revision
|
# find changes in the revision
|
||||||
editor = svn.repos.ChangeCollector(repo.fs, fsroot, pool)
|
editor = svn.repos.RevisionChangeCollector(repo.fs, rev, pool)
|
||||||
e_ptr, e_baton = svn.delta.make_editor(editor, pool)
|
e_ptr, e_baton = svn.delta.make_editor(editor, pool)
|
||||||
svn.repos.svn_repos_replay(fsroot, e_ptr, e_baton, pool)
|
svn.repos.svn_repos_replay(fsroot, e_ptr, e_baton, pool)
|
||||||
|
|
||||||
@@ -169,35 +168,22 @@ class SvnRev:
|
|||||||
if change.item_kind != svn.core.svn_node_file: continue
|
if change.item_kind != svn.core.svn_node_file: continue
|
||||||
|
|
||||||
# deal with the change types we handle
|
# deal with the change types we handle
|
||||||
action = None
|
|
||||||
base_root = None
|
base_root = None
|
||||||
base_path = change.base_path
|
|
||||||
if change.base_path:
|
if change.base_path:
|
||||||
base_root = self._get_root_for_rev(change.base_rev)
|
base_root = self._get_root_for_rev(change.base_rev)
|
||||||
|
|
||||||
# figure out what kind of change this is, and get a diff
|
if not change.path:
|
||||||
# object for it. note that prior to 1.4 Subversion's
|
|
||||||
# bindings didn't give us change.action, but that's okay
|
|
||||||
# because back then deleted paths always had a change.path
|
|
||||||
# of None.
|
|
||||||
if hasattr(change, 'action') \
|
|
||||||
and change.action == svn.repos.CHANGE_ACTION_DELETE:
|
|
||||||
action = 'remove'
|
|
||||||
elif not change.path:
|
|
||||||
action = 'remove'
|
action = 'remove'
|
||||||
elif change.added:
|
elif change.added:
|
||||||
action = 'add'
|
action = 'add'
|
||||||
else:
|
else:
|
||||||
action = 'change'
|
action = 'change'
|
||||||
|
|
||||||
if action == 'remove':
|
diffobj = svn.fs.FileDiff(base_root and base_root or None,
|
||||||
diffobj = svn.fs.FileDiff(base_root, base_path, None, None,
|
base_root and change.base_path or None,
|
||||||
|
change.path and fsroot or None,
|
||||||
|
change.path and change.path or None,
|
||||||
subpool, [])
|
subpool, [])
|
||||||
else:
|
|
||||||
diffobj = svn.fs.FileDiff(base_root, base_path,
|
|
||||||
fsroot, change.path,
|
|
||||||
subpool, [])
|
|
||||||
|
|
||||||
diff_fp = diffobj.get_pipe()
|
diff_fp = diffobj.get_pipe()
|
||||||
plus, minus = _get_diff_counts(diff_fp)
|
plus, minus = _get_diff_counts(diff_fp)
|
||||||
self.changes.append((path, action, plus, minus))
|
self.changes.append((path, action, plus, minus))
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -39,7 +39,7 @@ def _parse(hdr, result):
|
|||||||
while pos < len(hdr):
|
while pos < len(hdr):
|
||||||
name = _re_token.match(hdr, pos)
|
name = _re_token.match(hdr, pos)
|
||||||
if not name:
|
if not name:
|
||||||
raise AcceptLanguageParseError()
|
raise AcceptParseError()
|
||||||
a = result.item_class(string.lower(name.group(1)))
|
a = result.item_class(string.lower(name.group(1)))
|
||||||
pos = name.end()
|
pos = name.end()
|
||||||
while 1:
|
while 1:
|
||||||
@@ -210,7 +210,7 @@ class _LanguageSelector:
|
|||||||
def append(self, item):
|
def append(self, item):
|
||||||
self.requested.append(item)
|
self.requested.append(item)
|
||||||
|
|
||||||
class AcceptLanguageParseError(Exception):
|
class AcceptParseError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _test():
|
def _test():
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
@@ -31,8 +31,10 @@ import os
|
|||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
|
import cgi
|
||||||
import vclib
|
import vclib
|
||||||
import sapi
|
import vclib.ccvs.blame
|
||||||
|
|
||||||
|
|
||||||
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
|
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
|
||||||
|
|
||||||
@@ -80,7 +82,7 @@ class HTMLBlameSource:
|
|||||||
diff_url = None
|
diff_url = None
|
||||||
if item.prev_rev:
|
if item.prev_rev:
|
||||||
diff_url = '%sr1=%s&r2=%s' % (self.diff_url, item.prev_rev, item.rev)
|
diff_url = '%sr1=%s&r2=%s' % (self.diff_url, item.prev_rev, item.rev)
|
||||||
thisline = link_includes(sapi.escape(item.text), self.repos,
|
thisline = link_includes(cgi.escape(item.text), self.repos,
|
||||||
self.path_parts, self.include_url)
|
self.path_parts, self.include_url)
|
||||||
return _item(text=thisline, line_number=item.line_number,
|
return _item(text=thisline, line_number=item.line_number,
|
||||||
rev=item.rev, prev_rev=item.prev_rev,
|
rev=item.rev, prev_rev=item.prev_rev,
|
||||||
@@ -98,7 +100,6 @@ class _item:
|
|||||||
|
|
||||||
|
|
||||||
def make_html(root, rcs_path):
|
def make_html(root, rcs_path):
|
||||||
import vclib.ccvs.blame
|
|
||||||
bs = vclib.ccvs.blame.BlameSource(os.path.join(root, rcs_path))
|
bs = vclib.ccvs.blame.BlameSource(os.path.join(root, rcs_path))
|
||||||
|
|
||||||
count = bs.num_lines
|
count = bs.num_lines
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -19,8 +19,6 @@ import os
|
|||||||
import string
|
import string
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import re
|
|
||||||
import vclib
|
|
||||||
|
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
@@ -41,7 +39,7 @@ import vclib
|
|||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
_sections = ('general', 'options', 'cvsdb', 'templates')
|
_sections = ('general', 'options', 'cvsdb', 'templates')
|
||||||
_force_multi_value = ('cvs_roots', 'forbidden', 'forbiddenre',
|
_force_multi_value = ('cvs_roots', 'forbidden',
|
||||||
'svn_roots', 'languages', 'kv_files',
|
'svn_roots', 'languages', 'kv_files',
|
||||||
'root_parents')
|
'root_parents')
|
||||||
|
|
||||||
@@ -153,8 +151,7 @@ class Config:
|
|||||||
self.general.svn_path = ''
|
self.general.svn_path = ''
|
||||||
self.general.mime_types_file = ''
|
self.general.mime_types_file = ''
|
||||||
self.general.address = '<a href="mailto:user@insert.your.domain.here">No admin address has been configured</a>'
|
self.general.address = '<a href="mailto:user@insert.your.domain.here">No admin address has been configured</a>'
|
||||||
self.general.forbidden = []
|
self.general.forbidden = ()
|
||||||
self.general.forbiddenre = []
|
|
||||||
self.general.kv_files = [ ]
|
self.general.kv_files = [ ]
|
||||||
self.general.languages = ['en-us']
|
self.general.languages = ['en-us']
|
||||||
|
|
||||||
@@ -225,52 +222,9 @@ class Config:
|
|||||||
self.options.http_expiration_time = 600
|
self.options.http_expiration_time = 600
|
||||||
self.options.generate_etags = 1
|
self.options.generate_etags = 1
|
||||||
|
|
||||||
def is_forbidden(self, root, path_parts, pathtype):
|
def is_forbidden(self, module):
|
||||||
# If we don't have a root and path to check, get outta here.
|
if not module:
|
||||||
if not (root and path_parts):
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Give precedence to the new 'forbiddenre' stuff first.
|
|
||||||
if self.general.forbiddenre:
|
|
||||||
|
|
||||||
# Join the root and path-parts together into one path-like thing.
|
|
||||||
root_and_path = string.join([root] + path_parts, "/")
|
|
||||||
if pathtype == vclib.DIR:
|
|
||||||
root_and_path = root_and_path + '/'
|
|
||||||
|
|
||||||
# If we still have a list of strings, replace those suckers with
|
|
||||||
# lists of (compiled_regex, negation_flag)
|
|
||||||
if type(self.general.forbiddenre[0]) == type(""):
|
|
||||||
for i in range(len(self.general.forbiddenre)):
|
|
||||||
pat = self.general.forbiddenre[i]
|
|
||||||
if pat[0] == '!':
|
|
||||||
self.general.forbiddenre[i] = (re.compile(pat[1:]), 1)
|
|
||||||
else:
|
|
||||||
self.general.forbiddenre[i] = (re.compile(pat), 0)
|
|
||||||
|
|
||||||
# Do the forbiddenness test.
|
|
||||||
default = 0
|
|
||||||
for (pat, negated) in self.general.forbiddenre:
|
|
||||||
match = pat.search(root_and_path)
|
|
||||||
if negated:
|
|
||||||
default = 1
|
|
||||||
if match:
|
|
||||||
return 0
|
|
||||||
elif match:
|
|
||||||
return 1
|
|
||||||
return default
|
|
||||||
|
|
||||||
# If no 'forbiddenre' is in use, we check 'forbidden', which only
|
|
||||||
# looks at the top-most directory.
|
|
||||||
elif self.general.forbidden:
|
|
||||||
|
|
||||||
# A root and a single non-directory path component? That's not
|
|
||||||
# a module.
|
|
||||||
if len(path_parts) == 1 and pathtype != vclib.DIR:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
# Do the forbiddenness test.
|
|
||||||
module = path_parts[0]
|
|
||||||
default = 0
|
default = 0
|
||||||
for pat in self.general.forbidden:
|
for pat in self.general.forbidden:
|
||||||
if pat[0] == '!':
|
if pat[0] == '!':
|
||||||
@@ -281,9 +235,6 @@ class Config:
|
|||||||
return 1
|
return 1
|
||||||
return default
|
return default
|
||||||
|
|
||||||
# No forbiddenness configuration? Just allow it.
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def _parse_roots(config_name, config_value):
|
def _parse_roots(config_name, config_value):
|
||||||
roots = { }
|
roots = { }
|
||||||
|
17
lib/cvsdb.py
17
lib/cvsdb.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -29,12 +29,13 @@ error = "cvsdb error"
|
|||||||
## complient database interface
|
## complient database interface
|
||||||
|
|
||||||
class CheckinDatabase:
|
class CheckinDatabase:
|
||||||
def __init__(self, host, port, user, passwd, database):
|
def __init__(self, host, port, user, passwd, database, row_limit):
|
||||||
self._host = host
|
self._host = host
|
||||||
self._port = port
|
self._port = port
|
||||||
self._user = user
|
self._user = user
|
||||||
self._passwd = passwd
|
self._passwd = passwd
|
||||||
self._database = database
|
self._database = database
|
||||||
|
self._row_limit = row_limit
|
||||||
|
|
||||||
## database lookup caches
|
## database lookup caches
|
||||||
self._get_cache = {}
|
self._get_cache = {}
|
||||||
@@ -348,11 +349,13 @@ class CheckinDatabase:
|
|||||||
conditions = string.join(joinConds + condList, " AND ")
|
conditions = string.join(joinConds + condList, " AND ")
|
||||||
conditions = conditions and "WHERE %s" % conditions
|
conditions = conditions and "WHERE %s" % conditions
|
||||||
|
|
||||||
## apply the query's row limit, if any (so we avoid really
|
## limit the number of rows requested or we could really slam
|
||||||
## slamming a server with a large database)
|
## a server with a large database
|
||||||
limit = ""
|
limit = ""
|
||||||
if query.limit:
|
if query.limit:
|
||||||
limit = "LIMIT %s" % (str(query.limit))
|
limit = "LIMIT %s" % (str(query.limit))
|
||||||
|
elif self._row_limit:
|
||||||
|
limit = "LIMIT %s" % (str(self._row_limit))
|
||||||
|
|
||||||
sql = "SELECT checkins.* FROM %s %s %s %s" % (
|
sql = "SELECT checkins.* FROM %s %s %s %s" % (
|
||||||
tables, conditions, order_by, limit)
|
tables, conditions, order_by, limit)
|
||||||
@@ -591,8 +594,8 @@ class QueryEntry:
|
|||||||
self.data = data
|
self.data = data
|
||||||
self.match = match
|
self.match = match
|
||||||
|
|
||||||
## CheckinDatabaseQuery is an object which contains the search
|
## CheckinDatabaseQueryData is a object which contains the search parameters
|
||||||
## parameters for a query to the Checkin Database
|
## for a query to the CheckinDatabase
|
||||||
class CheckinDatabaseQuery:
|
class CheckinDatabaseQuery:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
## sorting
|
## sorting
|
||||||
@@ -679,7 +682,7 @@ def ConnectDatabase(cfg, readonly=0):
|
|||||||
user = cfg.cvsdb.user
|
user = cfg.cvsdb.user
|
||||||
passwd = cfg.cvsdb.passwd
|
passwd = cfg.cvsdb.passwd
|
||||||
db = CheckinDatabase(cfg.cvsdb.host, cfg.cvsdb.port, user, passwd,
|
db = CheckinDatabase(cfg.cvsdb.host, cfg.cvsdb.port, user, passwd,
|
||||||
cfg.cvsdb.database_name)
|
cfg.cvsdb.database_name, cfg.cvsdb.row_limit)
|
||||||
db.Connect()
|
db.Connect()
|
||||||
return db
|
return db
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
14
lib/debug.py
14
lib/debug.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -38,17 +38,13 @@ if SHOW_TIMES:
|
|||||||
else:
|
else:
|
||||||
_times[which] = t
|
_times[which] = t
|
||||||
|
|
||||||
def t_dump(out):
|
def dump():
|
||||||
out.write('<div>')
|
for name, value in _times.items():
|
||||||
names = _times.keys()
|
print '%s: %.6f<br />' % (name, value)
|
||||||
names.sort()
|
|
||||||
for name in names:
|
|
||||||
out.write('%s: %.6fs<br/>\n' % (name, _times[name]))
|
|
||||||
out.write('</div>')
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
t_start = t_end = t_dump = lambda *args: None
|
t_start = t_end = dump = lambda *args: None
|
||||||
|
|
||||||
|
|
||||||
class ViewVCException:
|
class ViewVCException:
|
||||||
|
@@ -200,7 +200,7 @@ Directives
|
|||||||
equivalent to "[CALLBACK QUAL_NAME]"
|
equivalent to "[CALLBACK QUAL_NAME]"
|
||||||
"""
|
"""
|
||||||
#
|
#
|
||||||
# Copyright (C) 2001-2007 Greg Stein. All Rights Reserved.
|
# Copyright (C) 2001-2005 Greg Stein. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# modification, are permitted provided that the following conditions are
|
# modification, are permitted provided that the following conditions are
|
||||||
|
20
lib/idiff.py
20
lib/idiff.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -20,7 +20,7 @@ import difflib
|
|||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import ezt
|
import ezt
|
||||||
import sapi
|
import cgi
|
||||||
|
|
||||||
def sidebyside(fromlines, tolines, context):
|
def sidebyside(fromlines, tolines, context):
|
||||||
"""Generate side by side diff"""
|
"""Generate side by side diff"""
|
||||||
@@ -49,18 +49,18 @@ def _mdiff_split(flag, (line_number, text)):
|
|||||||
while True:
|
while True:
|
||||||
m = _re_mdiff.search(text, pos)
|
m = _re_mdiff.search(text, pos)
|
||||||
if not m:
|
if not m:
|
||||||
segments.append(_item(text=sapi.escape(text[pos:]), type=None))
|
segments.append(_item(text=cgi.escape(text[pos:]), type=None))
|
||||||
break
|
break
|
||||||
|
|
||||||
if m.start() > pos:
|
if m.start() > pos:
|
||||||
segments.append(_item(text=sapi.escape(text[pos:m.start()]), type=None))
|
segments.append(_item(text=cgi.escape(text[pos:m.start()]), type=None))
|
||||||
|
|
||||||
if m.group(1) == "+":
|
if m.group(1) == "+":
|
||||||
segments.append(_item(text=sapi.escape(m.group(2)), type="add"))
|
segments.append(_item(text=cgi.escape(m.group(2)), type="add"))
|
||||||
elif m.group(1) == "-":
|
elif m.group(1) == "-":
|
||||||
segments.append(_item(text=sapi.escape(m.group(2)), type="remove"))
|
segments.append(_item(text=cgi.escape(m.group(2)), type="remove"))
|
||||||
elif m.group(1) == "^":
|
elif m.group(1) == "^":
|
||||||
segments.append(_item(text=sapi.escape(m.group(2)), type="change"))
|
segments.append(_item(text=cgi.escape(m.group(2)), type="change"))
|
||||||
|
|
||||||
pos = m.end()
|
pos = m.end()
|
||||||
|
|
||||||
@@ -166,12 +166,12 @@ def _differ_split(row, guide):
|
|||||||
|
|
||||||
for m in _re_differ.finditer(guide, pos):
|
for m in _re_differ.finditer(guide, pos):
|
||||||
if m.start() > pos:
|
if m.start() > pos:
|
||||||
segments.append(_item(text=sapi.escape(line[pos:m.start()]), type=None))
|
segments.append(_item(text=cgi.escape(line[pos:m.start()]), type=None))
|
||||||
segments.append(_item(text=sapi.escape(line[m.start():m.end()]),
|
segments.append(_item(text=cgi.escape(line[m.start():m.end()]),
|
||||||
type="change"))
|
type="change"))
|
||||||
pos = m.end()
|
pos = m.end()
|
||||||
|
|
||||||
segments.append(_item(text=sapi.escape(line[pos:]), type=None))
|
segments.append(_item(text=cgi.escape(line[pos:]), type=None))
|
||||||
|
|
||||||
return _item(gap=ezt.boolean(gap), type=type, segments=segments,
|
return _item(gap=ezt.boolean(gap), type=type, segments=segments,
|
||||||
left_number=left_number, right_number=right_number)
|
left_number=left_number, right_number=right_number)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
39
lib/query.py
39
lib/query.py
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -25,7 +25,6 @@ import time
|
|||||||
|
|
||||||
import cvsdb
|
import cvsdb
|
||||||
import viewvc
|
import viewvc
|
||||||
import vclib
|
|
||||||
import ezt
|
import ezt
|
||||||
import debug
|
import debug
|
||||||
import urllib
|
import urllib
|
||||||
@@ -217,9 +216,8 @@ def decode_command(cmd):
|
|||||||
else:
|
else:
|
||||||
return "exact"
|
return "exact"
|
||||||
|
|
||||||
def form_to_cvsdb_query(cfg, form_data):
|
def form_to_cvsdb_query(form_data):
|
||||||
query = cvsdb.CreateCheckinQuery()
|
query = cvsdb.CreateCheckinQuery()
|
||||||
query.SetLimit(cfg.cvsdb.row_limit)
|
|
||||||
|
|
||||||
if form_data.repository:
|
if form_data.repository:
|
||||||
for cmd, str in listparse_string(form_data.repository):
|
for cmd, str in listparse_string(form_data.repository):
|
||||||
@@ -284,8 +282,10 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
|
|||||||
ob.log = ' '
|
ob.log = ' '
|
||||||
|
|
||||||
for commit in files:
|
for commit in files:
|
||||||
parts = filter(None, string.split(commit.GetDirectory(), '/'))
|
dir_parts = filter(None, string.split(commit.GetDirectory(), '/'))
|
||||||
if parts and cfg.options.hide_cvsroot and parts[0] == 'CVSROOT':
|
if dir_parts \
|
||||||
|
and ((dir_parts[0] == 'CVSROOT' and cfg.options.hide_cvsroot) \
|
||||||
|
or cfg.is_forbidden(dir_parts[0])):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ctime = commit.GetTime()
|
ctime = commit.GetTime()
|
||||||
@@ -304,11 +304,6 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
|
|||||||
file = (directory and directory + "/") + commit.GetFile()
|
file = (directory and directory + "/") + commit.GetFile()
|
||||||
cvsroot_name = cvsroots.get(repository)
|
cvsroot_name = cvsroots.get(repository)
|
||||||
|
|
||||||
## skip forbidden files
|
|
||||||
if cfg.is_forbidden(cvsroot_name,
|
|
||||||
filter(None, string.split(file, "/")), vclib.FILE):
|
|
||||||
continue
|
|
||||||
|
|
||||||
## if we couldn't find the cvsroot path configured in the
|
## if we couldn't find the cvsroot path configured in the
|
||||||
## viewvc.conf file, then don't make the link
|
## viewvc.conf file, then don't make the link
|
||||||
if cvsroot_name:
|
if cvsroot_name:
|
||||||
@@ -339,7 +334,7 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
|
|||||||
return ob
|
return ob
|
||||||
|
|
||||||
def run_query(server, cfg, form_data, viewvc_link):
|
def run_query(server, cfg, form_data, viewvc_link):
|
||||||
query = form_to_cvsdb_query(cfg, form_data)
|
query = form_to_cvsdb_query(form_data)
|
||||||
db = cvsdb.ConnectDatabaseReadOnly(cfg)
|
db = cvsdb.ConnectDatabaseReadOnly(cfg)
|
||||||
db.RunQuery(query)
|
db.RunQuery(query)
|
||||||
|
|
||||||
@@ -350,7 +345,7 @@ def run_query(server, cfg, form_data, viewvc_link):
|
|||||||
files = [ ]
|
files = [ ]
|
||||||
|
|
||||||
cvsroots = {}
|
cvsroots = {}
|
||||||
rootitems = cfg.general.svn_roots.items() + cfg.general.cvs_roots.items()
|
rootitems = cfg.general.cvs_roots.items() + cfg.general.svn_roots.items()
|
||||||
for key, value in rootitems:
|
for key, value in rootitems:
|
||||||
cvsroots[cvsdb.CleanRepository(value)] = key
|
cvsroots[cvsdb.CleanRepository(value)] = key
|
||||||
|
|
||||||
@@ -371,13 +366,6 @@ def run_query(server, cfg, form_data, viewvc_link):
|
|||||||
commits.append(build_commit(server, cfg, current_desc, files,
|
commits.append(build_commit(server, cfg, current_desc, files,
|
||||||
cvsroots, viewvc_link))
|
cvsroots, viewvc_link))
|
||||||
|
|
||||||
# Strip out commits that don't have any files attached to them. The
|
|
||||||
# files probably aren't present because they've been blocked via
|
|
||||||
# forbiddenness.
|
|
||||||
def _only_with_files(commit):
|
|
||||||
return len(commit.files) > 0
|
|
||||||
commits = filter(_only_with_files, commits)
|
|
||||||
|
|
||||||
return commits
|
return commits
|
||||||
|
|
||||||
def main(server, cfg, viewvc_link):
|
def main(server, cfg, viewvc_link):
|
||||||
@@ -399,11 +387,12 @@ def main(server, cfg, viewvc_link):
|
|||||||
'cfg' : cfg,
|
'cfg' : cfg,
|
||||||
'address' : cfg.general.address,
|
'address' : cfg.general.address,
|
||||||
'vsn' : viewvc.__version__,
|
'vsn' : viewvc.__version__,
|
||||||
'repository' : server.escape(form_data.repository),
|
|
||||||
'branch' : server.escape(form_data.branch),
|
'repository' : server.escape(form_data.repository, 1),
|
||||||
'directory' : server.escape(form_data.directory),
|
'branch' : server.escape(form_data.branch, 1),
|
||||||
'file' : server.escape(form_data.file),
|
'directory' : server.escape(form_data.directory, 1),
|
||||||
'who' : server.escape(form_data.who),
|
'file' : server.escape(form_data.file, 1),
|
||||||
|
'who' : server.escape(form_data.who, 1),
|
||||||
'docroot' : cfg.options.docroot is None \
|
'docroot' : cfg.options.docroot is None \
|
||||||
and viewvc_link + '/' + viewvc.docroot_magic_path \
|
and viewvc_link + '/' + viewvc.docroot_magic_path \
|
||||||
or cfg.options.docroot,
|
or cfg.options.docroot,
|
||||||
|
34
lib/sapi.py
34
lib/sapi.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -20,7 +20,6 @@ import string
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import cgi
|
|
||||||
|
|
||||||
|
|
||||||
# global server object. It will be either a CgiServer or a proxy to
|
# global server object. It will be either a CgiServer or a proxy to
|
||||||
@@ -28,19 +27,6 @@ import cgi
|
|||||||
server = None
|
server = None
|
||||||
|
|
||||||
|
|
||||||
# Simple HTML string escaping. Note that we always escape the
|
|
||||||
# double-quote character -- ViewVC shouldn't ever need to preserve
|
|
||||||
# that character as-is, and sometimes needs to embed escaped values
|
|
||||||
# into HTML attributes.
|
|
||||||
def escape(s):
|
|
||||||
s = str(s)
|
|
||||||
s = string.replace(s, '&', '&')
|
|
||||||
s = string.replace(s, '>', '>')
|
|
||||||
s = string.replace(s, '<', '<')
|
|
||||||
s = string.replace(s, '"', """)
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.pageGlobals = {}
|
self.pageGlobals = {}
|
||||||
@@ -48,9 +34,6 @@ class Server:
|
|||||||
def self(self):
|
def self(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def escape(self, s):
|
|
||||||
return escape(s)
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -146,6 +129,9 @@ class CgiServer(Server):
|
|||||||
global server
|
global server
|
||||||
server = self
|
server = self
|
||||||
|
|
||||||
|
global cgi
|
||||||
|
import cgi
|
||||||
|
|
||||||
def addheader(self, name, value):
|
def addheader(self, name, value):
|
||||||
self.headers.append((name, value))
|
self.headers.append((name, value))
|
||||||
|
|
||||||
@@ -175,6 +161,9 @@ class CgiServer(Server):
|
|||||||
print 'This document is located <a href="%s">here</a>.' % url
|
print 'This document is located <a href="%s">here</a>.' % url
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
def escape(self, s, quote = None):
|
||||||
|
return cgi.escape(s, quote)
|
||||||
|
|
||||||
def getenv(self, name, value=None):
|
def getenv(self, name, value=None):
|
||||||
ret = os.environ.get(name, value)
|
ret = os.environ.get(name, value)
|
||||||
if self.iis and name == 'PATH_INFO' and ret:
|
if self.iis and name == 'PATH_INFO' and ret:
|
||||||
@@ -232,6 +221,9 @@ class AspServer(ThreadedServer):
|
|||||||
self.response.Redirect(url)
|
self.response.Redirect(url)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
def escape(self, s, quote = None):
|
||||||
|
return self.server.HTMLEncode(str(s))
|
||||||
|
|
||||||
def getenv(self, name, value = None):
|
def getenv(self, name, value = None):
|
||||||
ret = self.request.ServerVariables(name)()
|
ret = self.request.ServerVariables(name)()
|
||||||
if not type(ret) is types.UnicodeType:
|
if not type(ret) is types.UnicodeType:
|
||||||
@@ -293,6 +285,9 @@ class ModPythonServer(ThreadedServer):
|
|||||||
self.request = request
|
self.request = request
|
||||||
self.headerSent = 0
|
self.headerSent = 0
|
||||||
|
|
||||||
|
global cgi
|
||||||
|
import cgi
|
||||||
|
|
||||||
def addheader(self, name, value):
|
def addheader(self, name, value):
|
||||||
self.request.headers_out.add(name, value)
|
self.request.headers_out.add(name, value)
|
||||||
|
|
||||||
@@ -316,6 +311,9 @@ class ModPythonServer(ThreadedServer):
|
|||||||
% (url, url))
|
% (url, url))
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
def escape(self, s, quote = None):
|
||||||
|
return cgi.escape(s, quote)
|
||||||
|
|
||||||
def getenv(self, name, value = None):
|
def getenv(self, name, value = None):
|
||||||
try:
|
try:
|
||||||
return self.request.subprocess_env[name]
|
return self.request.subprocess_env[name]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -534,13 +534,10 @@ def _parse_co_header(fp):
|
|||||||
raise COMalformedOutput, "Unable to find filename in co output stream"
|
raise COMalformedOutput, "Unable to find filename in co output stream"
|
||||||
filename = match.group(1)
|
filename = match.group(1)
|
||||||
|
|
||||||
# look through subsequent lines for a revision. we might encounter
|
# look for a revision in the second line.
|
||||||
# some ignorable or problematic lines along the way.
|
|
||||||
while 1:
|
|
||||||
line = fp.readline()
|
line = fp.readline()
|
||||||
if not line:
|
if not line:
|
||||||
break
|
raise COMalformedOutput, "Missing second line from co output stream"
|
||||||
# look for a revision.
|
|
||||||
match = _re_co_revision.match(line)
|
match = _re_co_revision.match(line)
|
||||||
if match:
|
if match:
|
||||||
return filename, match.group(1)
|
return filename, match.group(1)
|
||||||
@@ -549,10 +546,19 @@ def _parse_co_header(fp):
|
|||||||
elif _re_co_warning.match(line):
|
elif _re_co_warning.match(line):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
break
|
|
||||||
|
|
||||||
raise COMalformedOutput, "Unable to find revision in co output stream"
|
raise COMalformedOutput, "Unable to find revision in co output stream"
|
||||||
|
|
||||||
|
# if we get here, the second line wasn't a revision, but it was a
|
||||||
|
# warning we can ignore. look for a revision in the third line.
|
||||||
|
line = fp.readline()
|
||||||
|
if not line:
|
||||||
|
raise COMalformedOutput, "Missing third line from co output stream"
|
||||||
|
match = _re_co_revision.match(line)
|
||||||
|
if match:
|
||||||
|
return filename, match.group(1)
|
||||||
|
raise COMalformedOutput, "Unable to find revision in co output stream"
|
||||||
|
|
||||||
|
|
||||||
# if your rlog doesn't use 77 '=' characters, then this must change
|
# if your rlog doesn't use 77 '=' characters, then this must change
|
||||||
LOG_END_MARKER = '=' * 77 + '\n'
|
LOG_END_MARKER = '=' * 77 + '\n'
|
||||||
ENTRY_END_MARKER = '-' * 28 + '\n'
|
ENTRY_END_MARKER = '-' * 28 + '\n'
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -25,7 +25,7 @@ _tt = TextTools
|
|||||||
_idchar_list = map(chr, range(33, 127)) + map(chr, range(160, 256))
|
_idchar_list = map(chr, range(33, 127)) + map(chr, range(160, 256))
|
||||||
_idchar_list.remove('$')
|
_idchar_list.remove('$')
|
||||||
_idchar_list.remove(',')
|
_idchar_list.remove(',')
|
||||||
#_idchar_list.remove('.') # leave as part of 'num' symbol
|
#_idchar_list.remove('.') leave as part of 'num' symbol
|
||||||
_idchar_list.remove(':')
|
_idchar_list.remove(':')
|
||||||
_idchar_list.remove(';')
|
_idchar_list.remove(';')
|
||||||
_idchar_list.remove('@')
|
_idchar_list.remove('@')
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -15,11 +15,9 @@
|
|||||||
import vclib
|
import vclib
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import stat
|
|
||||||
import string
|
import string
|
||||||
import cStringIO
|
import cStringIO
|
||||||
import signal
|
import signal
|
||||||
import shutil
|
|
||||||
import time
|
import time
|
||||||
import tempfile
|
import tempfile
|
||||||
import popen
|
import popen
|
||||||
@@ -239,9 +237,6 @@ class NodeHistory:
|
|||||||
|
|
||||||
|
|
||||||
def _get_history(svnrepos, full_name, rev, options={}):
|
def _get_history(svnrepos, full_name, rev, options={}):
|
||||||
if svnrepos.youngest == 0:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
fsroot = svnrepos._getroot(rev)
|
fsroot = svnrepos._getroot(rev)
|
||||||
show_all_logs = options.get('svn_show_all_dir_logs', 0)
|
show_all_logs = options.get('svn_show_all_dir_logs', 0)
|
||||||
if not show_all_logs:
|
if not show_all_logs:
|
||||||
@@ -504,36 +499,13 @@ class BlameSource:
|
|||||||
if os.sep != '/':
|
if os.sep != '/':
|
||||||
rootpath = string.replace(rootpath, os.sep, '/')
|
rootpath = string.replace(rootpath, os.sep, '/')
|
||||||
|
|
||||||
# Make a read-only temporary directory for Subversion to use as
|
|
||||||
# its runtime config dir. (Read-only because that will prevent
|
|
||||||
# Subversion from fleshing out all the default runtime config
|
|
||||||
# contents.)
|
|
||||||
self.config_dir = self._mkdtemp()
|
|
||||||
os.chmod(self.config_dir, stat.S_IRUSR | stat.S_IXUSR)
|
|
||||||
|
|
||||||
url = 'file://' + string.join([rootpath, fs_path], "/")
|
url = 'file://' + string.join([rootpath, fs_path], "/")
|
||||||
fp = popen.popen(svn_client_path,
|
fp = popen.popen(svn_client_path,
|
||||||
("blame",
|
('blame', "-r%d" % int(rev), "--non-interactive",
|
||||||
"-r%d" % int(rev),
|
|
||||||
"--non-interactive",
|
|
||||||
"--config-dir", self.config_dir,
|
|
||||||
"%s@%d" % (url, int(rev))),
|
"%s@%d" % (url, int(rev))),
|
||||||
'rb', 1)
|
'rb', 1)
|
||||||
self.fp = fp
|
self.fp = fp
|
||||||
|
|
||||||
def _mkdtemp(self):
|
|
||||||
### FIXME: When we require Python 2.3, this can go away.
|
|
||||||
for i in range(10):
|
|
||||||
dir = tempfile.mktemp()
|
|
||||||
try:
|
|
||||||
os.mkdir(dir, 0700)
|
|
||||||
return dir
|
|
||||||
except OSError, e:
|
|
||||||
if e.errno == errno.EEXIST:
|
|
||||||
continue # try again
|
|
||||||
raise
|
|
||||||
raise IOError, (errno.EEXIST, "No usable temporary directory name found")
|
|
||||||
|
|
||||||
def __getitem__(self, idx):
|
def __getitem__(self, idx):
|
||||||
if idx == self.idx:
|
if idx == self.idx:
|
||||||
return self.last
|
return self.last
|
||||||
@@ -558,13 +530,6 @@ class BlameSource:
|
|||||||
self.idx = idx
|
self.idx = idx
|
||||||
return item
|
return item
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
try:
|
|
||||||
if self.config_dir:
|
|
||||||
shutil.rmtree(self.config_dir)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class BlameSequencingError(Exception):
|
class BlameSequencingError(Exception):
|
||||||
pass
|
pass
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -20,7 +20,6 @@ import re
|
|||||||
import tempfile
|
import tempfile
|
||||||
import popen2
|
import popen2
|
||||||
import time
|
import time
|
||||||
import urllib
|
|
||||||
from vclib.svn import Revision, ChangedPath, _datestr_to_date, _compare_paths, _cleanup_path
|
from vclib.svn import Revision, ChangedPath, _datestr_to_date, _compare_paths, _cleanup_path
|
||||||
from svn import core, delta, client, wc, ra
|
from svn import core, delta, client, wc, ra
|
||||||
|
|
||||||
@@ -101,12 +100,8 @@ def created_rev(svnrepos, full_name, rev):
|
|||||||
kind = ra.svn_ra_check_path(svnrepos.ra_session, full_name, rev,
|
kind = ra.svn_ra_check_path(svnrepos.ra_session, full_name, rev,
|
||||||
svnrepos.pool)
|
svnrepos.pool)
|
||||||
if kind == core.svn_node_dir:
|
if kind == core.svn_node_dir:
|
||||||
retval = ra.svn_ra_get_dir(svnrepos.ra_session, full_name,
|
props = ra.svn_ra_get_dir(svnrepos.ra_session, full_name,
|
||||||
rev, svnrepos.pool)
|
rev, svnrepos.pool)
|
||||||
if type(retval) == type([]) and len(retval) == 3:
|
|
||||||
props = retval[2]
|
|
||||||
else: # compat with older (broken) bindings
|
|
||||||
props = retval
|
|
||||||
return int(props[core.SVN_PROP_ENTRY_COMMITTED_REV])
|
return int(props[core.SVN_PROP_ENTRY_COMMITTED_REV])
|
||||||
return core.SVN_INVALID_REVNUM
|
return core.SVN_INVALID_REVNUM
|
||||||
|
|
||||||
@@ -181,14 +176,12 @@ class LogCollector:
|
|||||||
# Changed paths have leading slashes
|
# Changed paths have leading slashes
|
||||||
changed_paths = paths.keys()
|
changed_paths = paths.keys()
|
||||||
changed_paths.sort(lambda a, b: _compare_paths(a, b))
|
changed_paths.sort(lambda a, b: _compare_paths(a, b))
|
||||||
copyfrom_path = copyfrom_rev = this_path = None
|
this_path = None
|
||||||
if self.path in changed_paths:
|
if self.path in changed_paths:
|
||||||
this_path = self.path
|
this_path = self.path
|
||||||
change = paths[self.path]
|
change = paths[self.path]
|
||||||
if change.copyfrom_path:
|
if change.copyfrom_path:
|
||||||
this_path = change.copyfrom_path
|
this_path = change.copyfrom_path
|
||||||
copyfrom_path = change.copyfrom_path[1:]
|
|
||||||
copyfrom_rev = change.copyfrom_rev
|
|
||||||
for changed_path in changed_paths:
|
for changed_path in changed_paths:
|
||||||
if changed_path != self.path:
|
if changed_path != self.path:
|
||||||
# If a parent of our path was copied, our "next previous"
|
# If a parent of our path was copied, our "next previous"
|
||||||
@@ -201,7 +194,7 @@ class LogCollector:
|
|||||||
if self.show_all_logs or this_path:
|
if self.show_all_logs or this_path:
|
||||||
date = _datestr_to_date(date, pool)
|
date = _datestr_to_date(date, pool)
|
||||||
entry = Revision(revision, date, author, message, None,
|
entry = Revision(revision, date, author, message, None,
|
||||||
self.path[1:], copyfrom_path, copyfrom_rev)
|
self.path[1:], None, None)
|
||||||
self.logs.append(entry)
|
self.logs.append(entry)
|
||||||
if this_path:
|
if this_path:
|
||||||
self.path = this_path
|
self.path = this_path
|
||||||
@@ -221,7 +214,7 @@ def get_logs(svnrepos, full_name, rev, files):
|
|||||||
rev, author, date, log, changes = \
|
rev, author, date, log, changes = \
|
||||||
_get_rev_details(svnrepos, entry.created_rev, subpool)
|
_get_rev_details(svnrepos, entry.created_rev, subpool)
|
||||||
rev_info_cache[entry.created_rev] = rev, author, date, log
|
rev_info_cache[entry.created_rev] = rev, author, date, log
|
||||||
file.rev = str(rev)
|
file.rev = rev
|
||||||
file.author = author
|
file.author = author
|
||||||
file.date = _datestr_to_date(date, subpool)
|
file.date = _datestr_to_date(date, subpool)
|
||||||
file.log = log
|
file.log = log
|
||||||
@@ -235,7 +228,7 @@ def temp_checkout(svnrepos, path, rev, pool):
|
|||||||
"""Check out file revision to temporary file"""
|
"""Check out file revision to temporary file"""
|
||||||
temp = tempfile.mktemp()
|
temp = tempfile.mktemp()
|
||||||
stream = core.svn_stream_from_aprfile(temp, pool)
|
stream = core.svn_stream_from_aprfile(temp, pool)
|
||||||
url = svnrepos._geturl(path)
|
url = svnrepos.rootpath + (path and '/' + path)
|
||||||
client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev),
|
client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev),
|
||||||
svnrepos.ctx, pool)
|
svnrepos.ctx, pool)
|
||||||
core.svn_stream_close(stream)
|
core.svn_stream_close(stream)
|
||||||
@@ -247,7 +240,7 @@ class SelfCleanFP:
|
|||||||
self._path = path
|
self._path = path
|
||||||
self._eof = 0
|
self._eof = 0
|
||||||
|
|
||||||
def read(self, len=None):
|
def read(self, len):
|
||||||
if len:
|
if len:
|
||||||
chunk = self._fp.read(len)
|
chunk = self._fp.read(len)
|
||||||
else:
|
else:
|
||||||
@@ -286,7 +279,7 @@ class SubversionRepository(vclib.Repository):
|
|||||||
self.rootpath = rootpath
|
self.rootpath = rootpath
|
||||||
|
|
||||||
# Setup the client context baton, complete with non-prompting authstuffs.
|
# Setup the client context baton, complete with non-prompting authstuffs.
|
||||||
ctx = client.svn_client_create_context()
|
ctx = client.svn_client_ctx_t()
|
||||||
providers = []
|
providers = []
|
||||||
providers.append(client.svn_client_get_simple_provider(pool))
|
providers.append(client.svn_client_get_simple_provider(pool))
|
||||||
providers.append(client.svn_client_get_username_provider(pool))
|
providers.append(client.svn_client_get_username_provider(pool))
|
||||||
@@ -324,10 +317,10 @@ class SubversionRepository(vclib.Repository):
|
|||||||
raise vclib.ItemNotFound(path_parts)
|
raise vclib.ItemNotFound(path_parts)
|
||||||
|
|
||||||
def openfile(self, path_parts, rev):
|
def openfile(self, path_parts, rev):
|
||||||
path = self._getpath(path_parts)
|
|
||||||
rev = self._getrev(rev)
|
rev = self._getrev(rev)
|
||||||
url = self._geturl(path)
|
url = self.rootpath
|
||||||
|
if len(path_parts):
|
||||||
|
url = self.rootpath + '/' + self._getpath(path_parts)
|
||||||
tmp_file = tempfile.mktemp()
|
tmp_file = tempfile.mktemp()
|
||||||
stream = core.svn_stream_from_aprfile(tmp_file, self.pool)
|
stream = core.svn_stream_from_aprfile(tmp_file, self.pool)
|
||||||
### rev here should be the last history revision of the URL
|
### rev here should be the last history revision of the URL
|
||||||
@@ -354,15 +347,18 @@ class SubversionRepository(vclib.Repository):
|
|||||||
get_logs(self, self._getpath(path_parts), self._getrev(rev), entries)
|
get_logs(self, self._getpath(path_parts), self._getrev(rev), entries)
|
||||||
|
|
||||||
def itemlog(self, path_parts, rev, options):
|
def itemlog(self, path_parts, rev, options):
|
||||||
path = self._getpath(path_parts)
|
full_name = self._getpath(path_parts)
|
||||||
rev = self._getrev(rev)
|
rev = self._getrev(rev)
|
||||||
url = self._geturl(path)
|
|
||||||
|
|
||||||
# It's okay if we're told to not show all logs on a file -- all
|
# It's okay if we're told to not show all logs on a file -- all
|
||||||
# the revisions should match correctly anyway.
|
# the revisions should match correctly anyway.
|
||||||
lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0))
|
lc = LogCollector(full_name, options.get('svn_show_all_dir_logs', 0))
|
||||||
|
dir_url = self.rootpath
|
||||||
|
if full_name:
|
||||||
|
dir_url = dir_url + '/' + full_name
|
||||||
|
|
||||||
cross_copies = options.get('svn_cross_copies', 0)
|
cross_copies = options.get('svn_cross_copies', 0)
|
||||||
client.svn_client_log([url], _rev2optrev(rev), _rev2optrev(1),
|
client.svn_client_log([dir_url], _rev2optrev(rev), _rev2optrev(1),
|
||||||
1, not cross_copies, lc.add_log,
|
1, not cross_copies, lc.add_log,
|
||||||
self.ctx, self.pool)
|
self.ctx, self.pool)
|
||||||
revs = lc.logs
|
revs = lc.logs
|
||||||
@@ -377,7 +373,7 @@ class SubversionRepository(vclib.Repository):
|
|||||||
def annotate(self, path_parts, rev):
|
def annotate(self, path_parts, rev):
|
||||||
path = self._getpath(path_parts)
|
path = self._getpath(path_parts)
|
||||||
rev = self._getrev(rev)
|
rev = self._getrev(rev)
|
||||||
url = self._geturl(path)
|
url = self.rootpath + (path and '/' + path)
|
||||||
|
|
||||||
blame_data = []
|
blame_data = []
|
||||||
|
|
||||||
@@ -427,17 +423,13 @@ class SubversionRepository(vclib.Repository):
|
|||||||
raise vclib.InvalidRevision(rev)
|
raise vclib.InvalidRevision(rev)
|
||||||
return rev
|
return rev
|
||||||
|
|
||||||
def _geturl(self, path=None):
|
|
||||||
if not path:
|
|
||||||
return self.rootpath
|
|
||||||
return self.rootpath + '/' + urllib.quote(path, "/*~")
|
|
||||||
|
|
||||||
def _get_dirents(self, path, rev):
|
def _get_dirents(self, path, rev):
|
||||||
dir_url = self._geturl(path)
|
|
||||||
if path:
|
if path:
|
||||||
key = str(rev) + '/' + path
|
key = str(rev) + '/' + path
|
||||||
|
dir_url = self.rootpath + '/' + path
|
||||||
else:
|
else:
|
||||||
key = str(rev)
|
key = str(rev)
|
||||||
|
dir_url = self.rootpath
|
||||||
dirents = self._dirent_cache.get(key)
|
dirents = self._dirent_cache.get(key)
|
||||||
if dirents:
|
if dirents:
|
||||||
return dirents
|
return dirents
|
||||||
|
523
lib/viewvc.py
523
lib/viewvc.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
__version__ = '1.0.13'
|
__version__ = '1.0.4'
|
||||||
|
|
||||||
# this comes from our library; measure the startup time
|
# this comes from our library; measure the startup time
|
||||||
import debug
|
import debug
|
||||||
@@ -25,6 +25,7 @@ debug.t_start('imports')
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import sapi
|
import sapi
|
||||||
|
import cgi
|
||||||
import string
|
import string
|
||||||
import urllib
|
import urllib
|
||||||
import mimetypes
|
import mimetypes
|
||||||
@@ -111,10 +112,7 @@ class Request:
|
|||||||
|
|
||||||
# process the Accept-Language: header
|
# process the Accept-Language: header
|
||||||
hal = server.getenv('HTTP_ACCEPT_LANGUAGE','')
|
hal = server.getenv('HTTP_ACCEPT_LANGUAGE','')
|
||||||
try:
|
|
||||||
self.lang_selector = accept.language(hal)
|
self.lang_selector = accept.language(hal)
|
||||||
except accept.AcceptLanguageParseError:
|
|
||||||
self.lang_selector = accept.language('en')
|
|
||||||
self.language = self.lang_selector.select_from(cfg.general.languages)
|
self.language = self.lang_selector.select_from(cfg.general.languages)
|
||||||
|
|
||||||
# load the key/value files, given the selected language
|
# load the key/value files, given the selected language
|
||||||
@@ -149,9 +147,6 @@ class Request:
|
|||||||
|
|
||||||
# Process the query params
|
# Process the query params
|
||||||
for name, values in self.server.params().items():
|
for name, values in self.server.params().items():
|
||||||
# we only care about the first value
|
|
||||||
value = values[0]
|
|
||||||
|
|
||||||
# patch up old queries that use 'cvsroot' to look like they used 'root'
|
# patch up old queries that use 'cvsroot' to look like they used 'root'
|
||||||
if name == 'cvsroot':
|
if name == 'cvsroot':
|
||||||
name = 'root'
|
name = 'root'
|
||||||
@@ -163,12 +158,12 @@ class Request:
|
|||||||
needs_redirect = 1
|
needs_redirect = 1
|
||||||
|
|
||||||
# validate the parameter
|
# validate the parameter
|
||||||
_validate_param(name, value)
|
_validate_param(name, values[0])
|
||||||
|
|
||||||
# if we're here, then the parameter is okay
|
# if we're here, then the parameter is okay
|
||||||
self.query_dict[name] = value
|
self.query_dict[name] = values[0]
|
||||||
|
|
||||||
# Resolve the view parameter into a handler function.
|
# handle view parameter
|
||||||
self.view_func = _views.get(self.query_dict.get('view', None),
|
self.view_func = _views.get(self.query_dict.get('view', None),
|
||||||
self.view_func)
|
self.view_func)
|
||||||
|
|
||||||
@@ -288,19 +283,13 @@ class Request:
|
|||||||
needs_redirect = 1
|
needs_redirect = 1
|
||||||
|
|
||||||
if self.repos and self.view_func is not redirect_pathrev:
|
if self.repos and self.view_func is not redirect_pathrev:
|
||||||
# If this is an intended-to-be-hidden CVSROOT path, complain.
|
|
||||||
if cfg.options.hide_cvsroot \
|
|
||||||
and is_cvsroot_path(self.roottype, path_parts):
|
|
||||||
raise debug.ViewVCException('%s: unknown location'
|
|
||||||
% self.where, '404 Not Found')
|
|
||||||
|
|
||||||
# Make sure path exists
|
# Make sure path exists
|
||||||
self.pathrev = pathrev = self.query_dict.get('pathrev')
|
self.pathrev = pathrev = self.query_dict.get('pathrev')
|
||||||
self.pathtype = _repos_pathtype(self.repos, path_parts, pathrev)
|
self.pathtype = _repos_pathtype(self.repos, path_parts, pathrev)
|
||||||
|
|
||||||
if self.pathtype is None:
|
if self.pathtype is None:
|
||||||
# Path doesn't exist, see if it could be an old-style ViewVC URL
|
# path doesn't exist, see if it could be an old-style ViewVC URL
|
||||||
# with a fake suffix.
|
# with a fake suffix
|
||||||
result = _strip_suffix('.diff', path_parts, pathrev, vclib.FILE, \
|
result = _strip_suffix('.diff', path_parts, pathrev, vclib.FILE, \
|
||||||
self.repos, view_diff) or \
|
self.repos, view_diff) or \
|
||||||
_strip_suffix('.tar.gz', path_parts, pathrev, vclib.DIR, \
|
_strip_suffix('.tar.gz', path_parts, pathrev, vclib.DIR, \
|
||||||
@@ -338,10 +327,10 @@ class Request:
|
|||||||
self.where = _path_join(attic_parts)
|
self.where = _path_join(attic_parts)
|
||||||
needs_redirect = 1
|
needs_redirect = 1
|
||||||
|
|
||||||
# If this is a forbidden location, stop now
|
# If this is a forbidden directory, stop now
|
||||||
if cfg.is_forbidden(self.rootname, self.path_parts, self.pathtype):
|
if self.path_parts and self.pathtype == vclib.DIR \
|
||||||
raise debug.ViewVCException('%s: unknown location' \
|
and cfg.is_forbidden(self.path_parts[0]):
|
||||||
% _path_join(self.path_parts),
|
raise debug.ViewVCException('%s: unknown location' % path_parts[0],
|
||||||
'404 Not Found')
|
'404 Not Found')
|
||||||
|
|
||||||
if self.view_func is None:
|
if self.view_func is None:
|
||||||
@@ -601,48 +590,34 @@ def _validate_param(name, value):
|
|||||||
this function throws an exception. Otherwise, it simply returns None.
|
this function throws an exception. Otherwise, it simply returns None.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# First things first -- check that we have a legal parameter name.
|
|
||||||
try:
|
try:
|
||||||
validator = _legal_params[name]
|
validator = _legal_params[name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise debug.ViewVCException(
|
raise debug.ViewVCException(
|
||||||
'An illegal parameter name was provided.',
|
'An illegal parameter name ("%s") was passed.' % name,
|
||||||
'400 Bad Request')
|
'400 Bad Request')
|
||||||
|
|
||||||
# Is there a validator? Is it a regex or a function? Validate if
|
|
||||||
# we can, returning without incident on valid input.
|
|
||||||
if validator is None:
|
if validator is None:
|
||||||
return
|
return
|
||||||
elif hasattr(validator, 'match'):
|
|
||||||
if validator.match(value):
|
# is the validator a regex?
|
||||||
return
|
if hasattr(validator, 'match'):
|
||||||
else:
|
if not validator.match(value):
|
||||||
if validator(value):
|
raise debug.ViewVCException(
|
||||||
|
'An illegal value ("%s") was passed as a parameter.' %
|
||||||
|
value, '400 Bad Request')
|
||||||
return
|
return
|
||||||
|
|
||||||
# If we get here, the input value isn't valid.
|
# the validator must be a function
|
||||||
raise debug.ViewVCException(
|
validator(value)
|
||||||
'An illegal value was provided for the "%s" parameter.' % (name),
|
|
||||||
'400 Bad Request')
|
|
||||||
|
|
||||||
def _validate_regex(value):
|
def _validate_regex(value):
|
||||||
|
# hmm. there isn't anything that we can do here.
|
||||||
|
|
||||||
### we need to watch the flow of these parameters through the system
|
### we need to watch the flow of these parameters through the system
|
||||||
### to ensure they don't hit the page unescaped. otherwise, these
|
### to ensure they don't hit the page unescaped. otherwise, these
|
||||||
### parameters could constitute a CSS attack.
|
### parameters could constitute a CSS attack.
|
||||||
try:
|
pass
|
||||||
re.compile(value)
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _validate_view(value):
|
|
||||||
# Return true iff VALUE is one of our allowed views.
|
|
||||||
return _views.has_key(value)
|
|
||||||
|
|
||||||
def _validate_mimetype(value):
|
|
||||||
# For security purposes, we only allow mimetypes from a predefined set
|
|
||||||
# thereof.
|
|
||||||
return value in (viewcvs_mime_type, alt_mime_type, 'text/plain')
|
|
||||||
|
|
||||||
# obvious things here. note that we don't need uppercase for alpha.
|
# obvious things here. note that we don't need uppercase for alpha.
|
||||||
_re_validate_alpha = re.compile('^[a-z]+$')
|
_re_validate_alpha = re.compile('^[a-z]+$')
|
||||||
@@ -651,13 +626,17 @@ _re_validate_number = re.compile('^[0-9]+$')
|
|||||||
# when comparing two revs, we sometimes construct REV:SYMBOL, so ':' is needed
|
# when comparing two revs, we sometimes construct REV:SYMBOL, so ':' is needed
|
||||||
_re_validate_revnum = re.compile('^[-_.a-zA-Z0-9:~\\[\\]/]*$')
|
_re_validate_revnum = re.compile('^[-_.a-zA-Z0-9:~\\[\\]/]*$')
|
||||||
|
|
||||||
|
# it appears that RFC 2045 also says these chars are legal: !#$%&'*+^{|}~`
|
||||||
|
# but woah... I'll just leave them out for now
|
||||||
|
_re_validate_mimetype = re.compile('^[-_.a-zA-Z0-9/]+$')
|
||||||
|
|
||||||
# date time values
|
# date time values
|
||||||
_re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d(:\d\d)?)?)?$')
|
_re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d(:\d\d)?)?)?$')
|
||||||
|
|
||||||
# the legal query parameters and their validation functions
|
# the legal query parameters and their validation functions
|
||||||
_legal_params = {
|
_legal_params = {
|
||||||
'root' : None,
|
'root' : None,
|
||||||
'view' : _validate_view,
|
'view' : None,
|
||||||
'search' : _validate_regex,
|
'search' : _validate_regex,
|
||||||
'p1' : None,
|
'p1' : None,
|
||||||
'p2' : None,
|
'p2' : None,
|
||||||
@@ -683,7 +662,7 @@ _legal_params = {
|
|||||||
'tr2' : _re_validate_revnum,
|
'tr2' : _re_validate_revnum,
|
||||||
'rev' : _re_validate_revnum,
|
'rev' : _re_validate_revnum,
|
||||||
'revision' : _re_validate_revnum,
|
'revision' : _re_validate_revnum,
|
||||||
'content-type' : _validate_mimetype,
|
'content-type' : _re_validate_mimetype,
|
||||||
|
|
||||||
# for query
|
# for query
|
||||||
'branch' : _validate_regex,
|
'branch' : _validate_regex,
|
||||||
@@ -699,6 +678,7 @@ _legal_params = {
|
|||||||
'mindate' : _re_validate_datetime,
|
'mindate' : _re_validate_datetime,
|
||||||
'maxdate' : _re_validate_datetime,
|
'maxdate' : _re_validate_datetime,
|
||||||
'format' : _re_validate_alpha,
|
'format' : _re_validate_alpha,
|
||||||
|
'limit' : _re_validate_number,
|
||||||
|
|
||||||
# for redirect_pathrev
|
# for redirect_pathrev
|
||||||
'orig_path' : None,
|
'orig_path' : None,
|
||||||
@@ -926,9 +906,6 @@ def is_viewable_image(mime_type):
|
|||||||
def is_text(mime_type):
|
def is_text(mime_type):
|
||||||
return not mime_type or mime_type[:5] == 'text/'
|
return not mime_type or mime_type[:5] == 'text/'
|
||||||
|
|
||||||
def is_cvsroot_path(roottype, path_parts):
|
|
||||||
return roottype == 'cvs' and path_parts and path_parts[0] == 'CVSROOT'
|
|
||||||
|
|
||||||
def is_plain_text(mime_type):
|
def is_plain_text(mime_type):
|
||||||
return not mime_type or mime_type == 'text/plain'
|
return not mime_type or mime_type == 'text/plain'
|
||||||
|
|
||||||
@@ -997,18 +974,13 @@ def get_file_view_info(request, where, rev=None, mime_type=None, pathrev=-1):
|
|||||||
_re_rewrite_url = re.compile('((http|https|ftp|file|svn|svn\+ssh)(://[-a-zA-Z0-9%.~:_/]+)((\?|\&)([-a-zA-Z0-9%.~:_]+)=([-a-zA-Z0-9%.~:_])+)*(#([-a-zA-Z0-9%.~:_]+)?)?)')
|
_re_rewrite_url = re.compile('((http|https|ftp|file|svn|svn\+ssh)(://[-a-zA-Z0-9%.~:_/]+)((\?|\&)([-a-zA-Z0-9%.~:_]+)=([-a-zA-Z0-9%.~:_])+)*(#([-a-zA-Z0-9%.~:_]+)?)?)')
|
||||||
_re_rewrite_email = re.compile('([-a-zA-Z0-9_.\+]+)@(([-a-zA-Z0-9]+\.)+[A-Za-z]{2,4})')
|
_re_rewrite_email = re.compile('([-a-zA-Z0-9_.\+]+)@(([-a-zA-Z0-9]+\.)+[A-Za-z]{2,4})')
|
||||||
def htmlify(html):
|
def htmlify(html):
|
||||||
html = sapi.escape(html)
|
html = cgi.escape(html)
|
||||||
html = re.sub(_re_rewrite_url, r'<a href="\1">\1</a>', html)
|
html = re.sub(_re_rewrite_url, r'<a href="\1">\1</a>', html)
|
||||||
html = re.sub(_re_rewrite_email, r'<a href="mailto:\1@\2">\1@\2</a>', html)
|
html = re.sub(_re_rewrite_email, r'<a href="mailto:\1@\2">\1@\2</a>', html)
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def format_log(log, cfg, htmlize=1):
|
def format_log(log, cfg):
|
||||||
if not log:
|
|
||||||
return log
|
|
||||||
if htmlize:
|
|
||||||
s = htmlify(log[:cfg.options.short_log_len])
|
s = htmlify(log[:cfg.options.short_log_len])
|
||||||
else:
|
|
||||||
s = sapi.escape(log[:cfg.options.short_log_len])
|
|
||||||
if len(log) > cfg.options.short_log_len:
|
if len(log) > cfg.options.short_log_len:
|
||||||
s = s + '...'
|
s = s + '...'
|
||||||
return s
|
return s
|
||||||
@@ -1332,7 +1304,7 @@ def markup_stream_python(fp, cfg):
|
|||||||
|
|
||||||
### It doesn't escape stuff quite right, nor does it munge URLs and
|
### It doesn't escape stuff quite right, nor does it munge URLs and
|
||||||
### mailtos as well as we do.
|
### mailtos as well as we do.
|
||||||
html = sapi.escape(fp.read())
|
html = cgi.escape(fp.read())
|
||||||
pp = py2html.PrettyPrint(PyFontify.fontify, "rawhtml", "color")
|
pp = py2html.PrettyPrint(PyFontify.fontify, "rawhtml", "color")
|
||||||
pp.set_mode_rawhtml_color()
|
pp.set_mode_rawhtml_color()
|
||||||
html = pp.fontify(html)
|
html = pp.fontify(html)
|
||||||
@@ -1485,7 +1457,7 @@ def prepare_hidden_values(params):
|
|||||||
hidden_values = []
|
hidden_values = []
|
||||||
for name, value in params.items():
|
for name, value in params.items():
|
||||||
hidden_values.append('<input type="hidden" name="%s" value="%s" />' %
|
hidden_values.append('<input type="hidden" name="%s" value="%s" />' %
|
||||||
(sapi.escape(name), sapi.escape(value)))
|
(name, value))
|
||||||
return string.join(hidden_values, '')
|
return string.join(hidden_values, '')
|
||||||
|
|
||||||
def sort_file_data(file_data, roottype, sortdir, sortby, group_dirs):
|
def sort_file_data(file_data, roottype, sortdir, sortby, group_dirs):
|
||||||
@@ -1565,9 +1537,16 @@ def view_directory(request):
|
|||||||
cfg.options.hide_attic))
|
cfg.options.hide_attic))
|
||||||
options["cvs_subdirs"] = (cfg.options.show_subdir_lastmod and
|
options["cvs_subdirs"] = (cfg.options.show_subdir_lastmod and
|
||||||
cfg.options.show_logs)
|
cfg.options.show_logs)
|
||||||
|
|
||||||
file_data = request.repos.listdir(request.path_parts, request.pathrev,
|
file_data = request.repos.listdir(request.path_parts, request.pathrev,
|
||||||
options)
|
options)
|
||||||
|
|
||||||
|
# Filter file list if a regex is specified
|
||||||
|
search_re = request.query_dict.get('search', '')
|
||||||
|
if cfg.options.use_re_search and search_re:
|
||||||
|
file_data = search_files(request.repos, request.path_parts, request.pathrev,
|
||||||
|
file_data, search_re)
|
||||||
|
|
||||||
# Retrieve log messages, authors, revision numbers, timestamps
|
# Retrieve log messages, authors, revision numbers, timestamps
|
||||||
request.repos.dirlogs(request.path_parts, request.pathrev, file_data, options)
|
request.repos.dirlogs(request.path_parts, request.pathrev, file_data, options)
|
||||||
|
|
||||||
@@ -1577,12 +1556,6 @@ def view_directory(request):
|
|||||||
sort_file_data(file_data, request.roottype, sortdir, sortby,
|
sort_file_data(file_data, request.roottype, sortdir, sortby,
|
||||||
cfg.options.sort_group_dirs)
|
cfg.options.sort_group_dirs)
|
||||||
|
|
||||||
# If a regex is specified, build a compiled form thereof for filtering
|
|
||||||
searchstr = None
|
|
||||||
search_re = request.query_dict.get('search', '')
|
|
||||||
if cfg.options.use_re_search and search_re:
|
|
||||||
searchstr = re.compile(search_re)
|
|
||||||
|
|
||||||
# loop through entries creating rows and changing these values
|
# loop through entries creating rows and changing these values
|
||||||
rows = [ ]
|
rows = [ ]
|
||||||
num_displayed = 0
|
num_displayed = 0
|
||||||
@@ -1614,14 +1587,13 @@ def view_directory(request):
|
|||||||
(file.kind == vclib.DIR and 'dir')
|
(file.kind == vclib.DIR and 'dir')
|
||||||
row.errors = file.errors
|
row.errors = file.errors
|
||||||
|
|
||||||
if cfg.is_forbidden(request.rootname, request.path_parts + [file.name],
|
if file.kind == vclib.DIR:
|
||||||
file.kind):
|
|
||||||
|
if (where == '') and (cfg.is_forbidden(file.name)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if file.kind == vclib.DIR:
|
if (request.roottype == 'cvs' and cfg.options.hide_cvsroot
|
||||||
if cfg.options.hide_cvsroot \
|
and where == '' and file.name == 'CVSROOT'):
|
||||||
and is_cvsroot_path(request.roottype,
|
|
||||||
request.path_parts + [file.name]):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
row.view_href = request.get_url(view_func=view_directory,
|
row.view_href = request.get_url(view_func=view_directory,
|
||||||
@@ -1649,17 +1621,10 @@ def view_directory(request):
|
|||||||
escape=1)
|
escape=1)
|
||||||
|
|
||||||
elif file.kind == vclib.FILE:
|
elif file.kind == vclib.FILE:
|
||||||
if searchstr is not None:
|
|
||||||
if request.roottype == 'cvs' and (file.errors or file.dead):
|
|
||||||
continue
|
|
||||||
if not search_file(request.repos, request.path_parts + [file.name],
|
|
||||||
request.pathrev, searchstr):
|
|
||||||
continue
|
|
||||||
if request.roottype == 'cvs' and file.dead:
|
if request.roottype == 'cvs' and file.dead:
|
||||||
num_dead = num_dead + 1
|
num_dead = num_dead + 1
|
||||||
if hideattic:
|
if hideattic:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
num_displayed = num_displayed + 1
|
num_displayed = num_displayed + 1
|
||||||
|
|
||||||
file_where = where_prefix + file.name
|
file_where = where_prefix + file.name
|
||||||
@@ -1732,9 +1697,6 @@ def view_directory(request):
|
|||||||
data['sortby_%s_href' % sortby] = request.get_url(params={'sortdir':
|
data['sortby_%s_href' % sortby] = request.get_url(params={'sortdir':
|
||||||
revsortdir},
|
revsortdir},
|
||||||
escape=1)
|
escape=1)
|
||||||
# CVS doesn't support sorting by rev
|
|
||||||
if request.roottype == "cvs":
|
|
||||||
data['sortby_rev_href'] = None
|
|
||||||
|
|
||||||
# set cvs-specific fields
|
# set cvs-specific fields
|
||||||
if request.roottype == 'cvs':
|
if request.roottype == 'cvs':
|
||||||
@@ -1929,12 +1891,10 @@ def view_log(request):
|
|||||||
# selected revision
|
# selected revision
|
||||||
selected_rev = request.query_dict.get('r1')
|
selected_rev = request.query_dict.get('r1')
|
||||||
|
|
||||||
paths_forbidden = {}
|
|
||||||
entries = [ ]
|
entries = [ ]
|
||||||
name_printed = { }
|
name_printed = { }
|
||||||
cvs = request.roottype == 'cvs'
|
cvs = request.roottype == 'cvs'
|
||||||
for rev in show_revs:
|
for rev in show_revs:
|
||||||
last_one = 0
|
|
||||||
entry = _item()
|
entry = _item()
|
||||||
entry.rev = rev.string
|
entry.rev = rev.string
|
||||||
entry.state = (cvs and rev.dead and 'dead')
|
entry.state = (cvs and rev.dead and 'dead')
|
||||||
@@ -1999,27 +1959,8 @@ def view_log(request):
|
|||||||
entry.vendor_branch = None
|
entry.vendor_branch = None
|
||||||
if rev.filename != request.where:
|
if rev.filename != request.where:
|
||||||
entry.orig_path = rev.filename
|
entry.orig_path = rev.filename
|
||||||
|
|
||||||
# If this path has been copied, check the copy source for
|
|
||||||
# forbiddenness. If it's forbidden, we'll a) pretend this is a
|
|
||||||
# regular add (instead of a copy), and b) stop traversing history.
|
|
||||||
if rev.copy_path:
|
|
||||||
if not paths_forbidden.has_key(rev.copy_path):
|
|
||||||
paths_forbidden[rev.copy_path] = \
|
|
||||||
cfg.is_forbidden(request.rootname,
|
|
||||||
_path_parts(rev.copy_path), pathtype)
|
|
||||||
|
|
||||||
if paths_forbidden[rev.copy_path]:
|
|
||||||
entry.prev = None
|
|
||||||
last_one = 1
|
|
||||||
else:
|
|
||||||
entry.copy_path = rev.copy_path
|
entry.copy_path = rev.copy_path
|
||||||
entry.copy_rev = rev.copy_rev
|
entry.copy_rev = rev.copy_rev
|
||||||
entry.copy_href = request.get_url(view_func=view_log,
|
|
||||||
where=rev.copy_path,
|
|
||||||
pathtype=vclib.FILE,
|
|
||||||
params={'pathrev': rev.copy_rev},
|
|
||||||
escape=1)
|
|
||||||
|
|
||||||
if entry.orig_path:
|
if entry.orig_path:
|
||||||
entry.orig_href = request.get_url(view_func=view_log,
|
entry.orig_href = request.get_url(view_func=view_log,
|
||||||
@@ -2028,6 +1969,14 @@ def view_log(request):
|
|||||||
params={'pathrev': rev.string},
|
params={'pathrev': rev.string},
|
||||||
escape=1)
|
escape=1)
|
||||||
|
|
||||||
|
if rev.copy_path:
|
||||||
|
entry.copy_href = request.get_url(view_func=view_log,
|
||||||
|
where=rev.copy_path,
|
||||||
|
pathtype=vclib.FILE,
|
||||||
|
params={'pathrev': rev.copy_rev},
|
||||||
|
escape=1)
|
||||||
|
|
||||||
|
|
||||||
# view/download links
|
# view/download links
|
||||||
if pathtype is vclib.FILE:
|
if pathtype is vclib.FILE:
|
||||||
entry.view_href, entry.download_href, entry.download_text_href, \
|
entry.view_href, entry.download_href, entry.download_text_href, \
|
||||||
@@ -2088,8 +2037,6 @@ def view_log(request):
|
|||||||
if entry.copy_path:
|
if entry.copy_path:
|
||||||
entry.copy_path = request.server.escape(entry.copy_path)
|
entry.copy_path = request.server.escape(entry.copy_path)
|
||||||
entries.append(entry)
|
entries.append(entry)
|
||||||
if last_one:
|
|
||||||
break
|
|
||||||
|
|
||||||
data = common_template_data(request)
|
data = common_template_data(request)
|
||||||
data.update({
|
data.update({
|
||||||
@@ -2295,23 +2242,58 @@ def view_cvsgraph(request):
|
|||||||
request.server.header()
|
request.server.header()
|
||||||
generate_page(request, "graph", data)
|
generate_page(request, "graph", data)
|
||||||
|
|
||||||
def search_file(repos, path_parts, rev, search_re):
|
def search_files(repos, path_parts, rev, files, search_re):
|
||||||
"""Return 1 iff the contents of the file at PATH_PARTS in REPOS as
|
""" Search files in a directory for a regular expression.
|
||||||
of revision REV matches regular expression SEARCH_RE."""
|
|
||||||
|
|
||||||
# Read in each line of a checked-out file, and then use re.search to
|
Does a check-out of each file in the directory. Only checks for
|
||||||
# search line.
|
the first match.
|
||||||
fp = repos.openfile(path_parts, rev)[0]
|
"""
|
||||||
matches = 0
|
|
||||||
|
# Pass in search regular expression. We check out
|
||||||
|
# each file and look for the regular expression. We then return the data
|
||||||
|
# for all files that match the regex.
|
||||||
|
|
||||||
|
# Compile to make sure we do this as fast as possible.
|
||||||
|
searchstr = re.compile(search_re)
|
||||||
|
|
||||||
|
# Will become list of files that have at least one match.
|
||||||
|
# new_file_list also includes directories.
|
||||||
|
new_file_list = [ ]
|
||||||
|
|
||||||
|
# Loop on every file (and directory)
|
||||||
|
for file in files:
|
||||||
|
# Is this a directory? If so, append name to new_file_list
|
||||||
|
# and move to next file.
|
||||||
|
if file.kind != vclib.FILE:
|
||||||
|
new_file_list.append(file)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Only files at this point
|
||||||
|
|
||||||
|
# Shouldn't search binary files, or should we?
|
||||||
|
# Should allow all text mime types to pass.
|
||||||
|
if not is_text(guess_mime(file.name)):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Only text files at this point
|
||||||
|
|
||||||
|
# Assign contents of checked out file to fp.
|
||||||
|
fp = repos.openfile(path_parts + [file.name], rev)[0]
|
||||||
|
|
||||||
|
# Read in each line, use re.search to search line.
|
||||||
|
# If successful, add file to new_file_list and break.
|
||||||
while 1:
|
while 1:
|
||||||
line = fp.readline()
|
line = fp.readline()
|
||||||
if not line:
|
if not line:
|
||||||
break
|
break
|
||||||
if search_re.search(line):
|
if searchstr.search(line):
|
||||||
matches = 1
|
new_file_list.append(file)
|
||||||
|
# close down the pipe (and wait for the child to terminate)
|
||||||
fp.close()
|
fp.close()
|
||||||
break
|
break
|
||||||
return matches
|
|
||||||
|
return new_file_list
|
||||||
|
|
||||||
|
|
||||||
def view_doc(request):
|
def view_doc(request):
|
||||||
"""Serve ViewVC static content locally.
|
"""Serve ViewVC static content locally.
|
||||||
@@ -2457,7 +2439,7 @@ class DiffSource:
|
|||||||
return _item(type='header',
|
return _item(type='header',
|
||||||
line_info_left=match.group(1),
|
line_info_left=match.group(1),
|
||||||
line_info_right=match.group(2),
|
line_info_right=match.group(2),
|
||||||
line_info_extra=spaced_html_text(match.group(3), self.cfg))
|
line_info_extra=match.group(3))
|
||||||
|
|
||||||
if line[0] == '\\':
|
if line[0] == '\\':
|
||||||
# \ No newline at end of file
|
# \ No newline at end of file
|
||||||
@@ -2580,9 +2562,12 @@ def diff_parse_headers(fp, diff_type, rev1, rev2, sym1=None, sym2=None):
|
|||||||
return date1, date2, flag, string.join(header_lines, '')
|
return date1, date2, flag, string.join(header_lines, '')
|
||||||
|
|
||||||
|
|
||||||
def _get_svn_location(request, base_rev, rev):
|
def _get_diff_path_parts(request, query_key, rev, base_rev):
|
||||||
repos = request.repos
|
if request.query_dict.has_key(query_key):
|
||||||
|
parts = _path_parts(request.query_dict[query_key])
|
||||||
|
elif request.roottype == 'svn':
|
||||||
try:
|
try:
|
||||||
|
repos = request.repos
|
||||||
parts = _path_parts(vclib.svn.get_location(repos, request.where,
|
parts = _path_parts(vclib.svn.get_location(repos, request.where,
|
||||||
repos._getrev(base_rev),
|
repos._getrev(base_rev),
|
||||||
repos._getrev(rev)))
|
repos._getrev(rev)))
|
||||||
@@ -2592,17 +2577,6 @@ def _get_svn_location(request, base_rev, rev):
|
|||||||
except vclib.ItemNotFound:
|
except vclib.ItemNotFound:
|
||||||
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
|
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
|
||||||
'to diff', '400 Bad Request')
|
'to diff', '400 Bad Request')
|
||||||
if request.cfg.is_forbidden(request.rootname, parts, vclib.FILE):
|
|
||||||
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
|
|
||||||
'to diff', '400 Bad Request')
|
|
||||||
return parts
|
|
||||||
|
|
||||||
|
|
||||||
def _get_diff_path_parts(request, query_key, rev, base_rev):
|
|
||||||
if request.query_dict.has_key(query_key):
|
|
||||||
parts = _path_parts(request.query_dict[query_key])
|
|
||||||
elif request.roottype == 'svn':
|
|
||||||
parts = _get_svn_location(request, base_rev, rev)
|
|
||||||
else:
|
else:
|
||||||
parts = request.path_parts
|
parts = request.path_parts
|
||||||
return parts
|
return parts
|
||||||
@@ -2922,11 +2896,6 @@ def generate_tarball(out, request, reldir, stack, dir_mtime=None):
|
|||||||
if cvs and (file.rev is None or file.dead):
|
if cvs and (file.rev is None or file.dead):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Skip forbidden files.
|
|
||||||
if request.cfg.is_forbidden(request.rootname, rep_path + [file.name],
|
|
||||||
file.kind):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# If we get here, we've seen at least one valid file in the
|
# 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
|
# current directory. For CVS, we need to make sure there are
|
||||||
# directory parents to contain it, so we flush the stack.
|
# directory parents to contain it, so we flush the stack.
|
||||||
@@ -2957,14 +2926,11 @@ def generate_tarball(out, request, reldir, stack, dir_mtime=None):
|
|||||||
if file.errors or file.kind != vclib.DIR:
|
if file.errors or file.kind != vclib.DIR:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Skip hidden directories (top-level only).
|
# Skip forbidden/hidden directories (top-level only).
|
||||||
if request.cfg.options.hide_cvsroot \
|
if not rep_path:
|
||||||
and is_cvsroot_path(request.roottype, rep_path + [file.name]):
|
if (request.cfg.is_forbidden(file.name)
|
||||||
continue
|
or (cvs and request.cfg.options.hide_cvsroot
|
||||||
|
and file.name == 'CVSROOT')):
|
||||||
# Skip forbidden subdirs.
|
|
||||||
if request.cfg.is_forbidden(request.rootname, rep_path + [file.name],
|
|
||||||
file.kind):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mtime = request.roottype == 'svn' and file.date or None
|
mtime = request.roottype == 'svn' and file.date or None
|
||||||
@@ -2993,9 +2959,8 @@ def download_tarball(request):
|
|||||||
|
|
||||||
def view_revision(request):
|
def view_revision(request):
|
||||||
if request.roottype == "cvs":
|
if request.roottype == "cvs":
|
||||||
raise debug.ViewVCException("Revision view not supported for CVS "
|
raise ViewVCException("Revision view not supported for CVS repositories "
|
||||||
"repositories at this time.",
|
"at this time.", "400 Bad Request")
|
||||||
"400 Bad Request")
|
|
||||||
|
|
||||||
data = common_template_data(request)
|
data = common_template_data(request)
|
||||||
query_dict = request.query_dict
|
query_dict = request.query_dict
|
||||||
@@ -3011,14 +2976,6 @@ def view_revision(request):
|
|||||||
if check_freshness(request, None, str(rev), weak=1):
|
if check_freshness(request, None, str(rev), weak=1):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Strip forbidden changed paths (we allow forbidden copyfrom-paths
|
|
||||||
# to leak through, though).
|
|
||||||
def _only_allowed(change):
|
|
||||||
return not request.cfg.is_forbidden(request.rootname,
|
|
||||||
_path_parts(change.filename),
|
|
||||||
change.pathtype)
|
|
||||||
changes = filter(_only_allowed, changes)
|
|
||||||
|
|
||||||
# Handle limit_changes parameter
|
# Handle limit_changes parameter
|
||||||
cfg_limit_changes = request.cfg.options.limit_changes
|
cfg_limit_changes = request.cfg.options.limit_changes
|
||||||
limit_changes = int(query_dict.get('limit_changes', cfg_limit_changes))
|
limit_changes = int(query_dict.get('limit_changes', cfg_limit_changes))
|
||||||
@@ -3044,22 +3001,8 @@ def view_revision(request):
|
|||||||
pathtype = (change.pathtype == vclib.FILE and 'file') \
|
pathtype = (change.pathtype == vclib.FILE and 'file') \
|
||||||
or (change.pathtype == vclib.DIR and 'dir') \
|
or (change.pathtype == vclib.DIR and 'dir') \
|
||||||
or None
|
or None
|
||||||
|
if (change.action == 'added' or change.action == 'replaced') \
|
||||||
# If this is an add or a replacement, we'll verify that copyfrom
|
and not change.is_copy:
|
||||||
# paths are readable (if this is a copy), and if not claim this
|
|
||||||
# isn't a copy after all. And if it ain't a copy (now or "after
|
|
||||||
# all"), we'll clear the text_mods and prop_mods flags.
|
|
||||||
if (change.action == 'added' or change.action == 'replaced'):
|
|
||||||
if change.is_copy \
|
|
||||||
and request.cfg.is_forbidden(request.rootname,
|
|
||||||
_path_parts(change.base_path),
|
|
||||||
change.pathtype):
|
|
||||||
change.is_copy = 0
|
|
||||||
if change.action == 'added':
|
|
||||||
change.base_path = None
|
|
||||||
change.base_rev = None
|
|
||||||
|
|
||||||
if not change.is_copy:
|
|
||||||
change.text_mods = 0
|
change.text_mods = 0
|
||||||
change.prop_mods = 0
|
change.prop_mods = 0
|
||||||
|
|
||||||
@@ -3166,22 +3109,19 @@ def view_queryform(request):
|
|||||||
data['query_action'], data['query_hidden_values'] = \
|
data['query_action'], data['query_hidden_values'] = \
|
||||||
request.get_form(view_func=view_query, params={'limit_changes': None})
|
request.get_form(view_func=view_query, params={'limit_changes': None})
|
||||||
|
|
||||||
def escaped_query_dict_get(itemname, itemdefault=''):
|
|
||||||
return request.server.escape(request.query_dict.get(itemname, itemdefault))
|
|
||||||
|
|
||||||
# default values ...
|
# default values ...
|
||||||
data['branch'] = escaped_query_dict_get('branch', '')
|
data['branch'] = request.query_dict.get('branch', '')
|
||||||
data['branch_match'] = escaped_query_dict_get('branch_match', 'exact')
|
data['branch_match'] = request.query_dict.get('branch_match', 'exact')
|
||||||
data['dir'] = escaped_query_dict_get('dir', '')
|
data['dir'] = request.query_dict.get('dir', '')
|
||||||
data['file'] = escaped_query_dict_get('file', '')
|
data['file'] = request.query_dict.get('file', '')
|
||||||
data['file_match'] = escaped_query_dict_get('file_match', 'exact')
|
data['file_match'] = request.query_dict.get('file_match', 'exact')
|
||||||
data['who'] = escaped_query_dict_get('who', '')
|
data['who'] = request.query_dict.get('who', '')
|
||||||
data['who_match'] = escaped_query_dict_get('who_match', 'exact')
|
data['who_match'] = request.query_dict.get('who_match', 'exact')
|
||||||
data['querysort'] = escaped_query_dict_get('querysort', 'date')
|
data['querysort'] = request.query_dict.get('querysort', 'date')
|
||||||
data['date'] = escaped_query_dict_get('date', 'hours')
|
data['date'] = request.query_dict.get('date', 'hours')
|
||||||
data['hours'] = escaped_query_dict_get('hours', '2')
|
data['hours'] = request.query_dict.get('hours', '2')
|
||||||
data['mindate'] = escaped_query_dict_get('mindate', '')
|
data['mindate'] = request.query_dict.get('mindate', '')
|
||||||
data['maxdate'] = escaped_query_dict_get('maxdate', '')
|
data['maxdate'] = request.query_dict.get('maxdate', '')
|
||||||
data['limit_changes'] = int(request.query_dict.get('limit_changes',
|
data['limit_changes'] = int(request.query_dict.get('limit_changes',
|
||||||
request.cfg.options.limit_changes))
|
request.cfg.options.limit_changes))
|
||||||
|
|
||||||
@@ -3279,23 +3219,27 @@ def prev_rev(rev):
|
|||||||
r = r[:-2]
|
r = r[:-2]
|
||||||
return string.join(r, '.')
|
return string.join(r, '.')
|
||||||
|
|
||||||
def build_commit(request, files, max_files, dir_strip, format):
|
def build_commit(request, files, limited_files, dir_strip):
|
||||||
"""Return a commit object build from the information in FILES, or
|
commit = _item(num_files=len(files), files=[])
|
||||||
None if no allowed files are present in the set. DIR_STRIP is the
|
commit.limited_files = ezt.boolean(limited_files)
|
||||||
path prefix to remove from the commit object's set of files. If
|
|
||||||
MAX_FILES is non-zero, it is used to limit the number of files
|
|
||||||
returned in the commit object. FORMAT is the requested output
|
|
||||||
format of the query request."""
|
|
||||||
|
|
||||||
author = files[0].GetAuthor()
|
|
||||||
date = files[0].GetTime()
|
|
||||||
desc = files[0].GetDescription()
|
desc = files[0].GetDescription()
|
||||||
commit_rev = files[0].GetRevision()
|
commit.log = htmlify(desc)
|
||||||
|
commit.short_log = format_log(desc, request.cfg)
|
||||||
|
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 = '%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))
|
||||||
|
else:
|
||||||
|
commit.rev = None
|
||||||
|
commit.rss_url = None
|
||||||
|
|
||||||
len_strip = len(dir_strip)
|
len_strip = len(dir_strip)
|
||||||
commit_files = []
|
|
||||||
num_allowed = 0
|
|
||||||
plus_count = 0
|
|
||||||
minus_count = 0
|
|
||||||
|
|
||||||
for f in files:
|
for f in files:
|
||||||
commit_time = f.GetTime()
|
commit_time = f.GetTime()
|
||||||
@@ -3313,15 +3257,7 @@ def build_commit(request, files, max_files, dir_strip, format):
|
|||||||
assert dirname[:len_strip] == dir_strip
|
assert dirname[:len_strip] == dir_strip
|
||||||
assert len(dirname) == len_strip or dirname[len(dir_strip)] == '/'
|
assert len(dirname) == len_strip or dirname[len(dir_strip)] == '/'
|
||||||
dirname = dirname[len_strip+1:]
|
dirname = dirname[len_strip+1:]
|
||||||
where = dirname and ("%s/%s" % (dirname, filename)) or filename
|
filename = dirname and ("%s/%s" % (dirname, filename)) or filename
|
||||||
|
|
||||||
# skip files in forbidden or hidden modules
|
|
||||||
path_parts = _path_parts(where)
|
|
||||||
if request.cfg.is_forbidden(request.rootname, path_parts, vclib.FILE):
|
|
||||||
continue
|
|
||||||
if request.cfg.options.hide_cvsroot \
|
|
||||||
and is_cvsroot_path(request.roottype, path_parts):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# In CVS, we can actually look at deleted revisions; in Subversion
|
# In CVS, we can actually look at deleted revisions; in Subversion
|
||||||
# we can't -- we'll look at the previous revision instead.
|
# we can't -- we'll look at the previous revision instead.
|
||||||
@@ -3337,14 +3273,14 @@ def build_commit(request, files, max_files, dir_strip, format):
|
|||||||
where=dirname, pathtype=vclib.DIR,
|
where=dirname, pathtype=vclib.DIR,
|
||||||
params=params, escape=1)
|
params=params, escape=1)
|
||||||
log_href = request.get_url(view_func=view_log,
|
log_href = request.get_url(view_func=view_log,
|
||||||
where=where, pathtype=vclib.FILE,
|
where=filename, pathtype=vclib.FILE,
|
||||||
params=params, escape=1)
|
params=params, escape=1)
|
||||||
diff_href = view_href = download_href = None
|
diff_href = view_href = download_href = None
|
||||||
view_href = request.get_url(view_func=view_markup,
|
view_href = request.get_url(view_func=view_markup,
|
||||||
where=where, pathtype=vclib.FILE,
|
where=filename, pathtype=vclib.FILE,
|
||||||
params=params, escape=1)
|
params=params, escape=1)
|
||||||
download_href = request.get_url(view_func=view_checkout,
|
download_href = request.get_url(view_func=view_checkout,
|
||||||
where=where, pathtype=vclib.FILE,
|
where=filename, pathtype=vclib.FILE,
|
||||||
params=params, escape=1)
|
params=params, escape=1)
|
||||||
if change_type == 'Change':
|
if change_type == 'Change':
|
||||||
diff_href_params = params.copy()
|
diff_href_params = params.copy()
|
||||||
@@ -3354,29 +3290,27 @@ def build_commit(request, files, max_files, dir_strip, format):
|
|||||||
'diff_format': None
|
'diff_format': None
|
||||||
})
|
})
|
||||||
diff_href = request.get_url(view_func=view_diff,
|
diff_href = request.get_url(view_func=view_diff,
|
||||||
where=where, pathtype=vclib.FILE,
|
where=filename, pathtype=vclib.FILE,
|
||||||
params=diff_href_params, escape=1)
|
params=diff_href_params, escape=1)
|
||||||
prefer_markup = ezt.boolean(default_view(guess_mime(filename),
|
prefer_markup = ezt.boolean(default_view(guess_mime(filename),
|
||||||
request.cfg) == view_markup)
|
request.cfg) == view_markup)
|
||||||
|
|
||||||
# Update plus/minus line change count.
|
# skip files in forbidden or hidden modules
|
||||||
plus = int(f.GetPlusCount())
|
dir_parts = filter(None, string.split(dirname, '/'))
|
||||||
minus = int(f.GetMinusCount())
|
if dir_parts \
|
||||||
plus_count = plus_count + plus
|
and ((dir_parts[0] == 'CVSROOT'
|
||||||
minus_count = minus_count + minus
|
and request.cfg.options.hide_cvsroot) \
|
||||||
|
or request.cfg.is_forbidden(dir_parts[0])):
|
||||||
num_allowed = num_allowed + 1
|
|
||||||
if max_files and num_allowed > max_files:
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
commit_files.append(_item(date=commit_time,
|
commit.files.append(_item(date=commit_time,
|
||||||
dir=request.server.escape(dirname),
|
dir=request.server.escape(dirname),
|
||||||
file=request.server.escape(filename),
|
file=request.server.escape(f.GetFile()),
|
||||||
author=request.server.escape(f.GetAuthor()),
|
author=request.server.escape(f.GetAuthor()),
|
||||||
rev=rev,
|
rev=rev,
|
||||||
branch=f.GetBranch(),
|
branch=f.GetBranch(),
|
||||||
plus=plus,
|
plus=int(f.GetPlusCount()),
|
||||||
minus=minus,
|
minus=int(f.GetMinusCount()),
|
||||||
type=change_type,
|
type=change_type,
|
||||||
dir_href=dir_href,
|
dir_href=dir_href,
|
||||||
log_href=log_href,
|
log_href=log_href,
|
||||||
@@ -3384,56 +3318,30 @@ def build_commit(request, files, max_files, dir_strip, format):
|
|||||||
download_href=download_href,
|
download_href=download_href,
|
||||||
prefer_markup=prefer_markup,
|
prefer_markup=prefer_markup,
|
||||||
diff_href=diff_href))
|
diff_href=diff_href))
|
||||||
|
|
||||||
# No files survived forbiddenness checks? Let's just pretend this
|
|
||||||
# little commit didn't happen, shall we?
|
|
||||||
if not len(commit_files):
|
|
||||||
return None
|
|
||||||
|
|
||||||
commit = _item(num_files=len(commit_files), files=commit_files,
|
|
||||||
plus=plus_count, minus=minus_count)
|
|
||||||
commit.limited_files = ezt.boolean(num_allowed > len(commit_files))
|
|
||||||
commit.log = htmlify(desc)
|
|
||||||
commit.short_log = format_log(desc, request.cfg, format != 'rss')
|
|
||||||
commit.author = request.server.escape(author)
|
|
||||||
commit.rss_date = make_rss_time_string(date, request.cfg)
|
|
||||||
if request.roottype == 'svn':
|
|
||||||
commit.rev = commit_rev
|
|
||||||
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))
|
|
||||||
else:
|
|
||||||
commit.rev = None
|
|
||||||
commit.rss_url = None
|
|
||||||
return commit
|
return commit
|
||||||
|
|
||||||
def query_backout(request, commits):
|
def query_backout(request, commits):
|
||||||
server_fp = get_writeready_server_file(request, 'text/plain')
|
request.server.header('text/plain')
|
||||||
if not commits:
|
if commits:
|
||||||
server_fp.write("""\
|
print '# This page can be saved as a shell script and executed.'
|
||||||
# No changes were selected by the query.
|
print '# It should be run at the top of your work area. It will update'
|
||||||
# There is nothing to back out.
|
print '# your working copy to back out the changes selected by the'
|
||||||
""")
|
print '# query.'
|
||||||
|
print
|
||||||
|
else:
|
||||||
|
print '# No changes were selected by the query.'
|
||||||
|
print '# There is nothing to back out.'
|
||||||
return
|
return
|
||||||
server_fp.write("""\
|
|
||||||
# This page can be saved as a shell script and executed.
|
|
||||||
# It should be run at the top of your work area. It will update
|
|
||||||
# your working copy to back out the changes selected by the
|
|
||||||
# query.
|
|
||||||
""")
|
|
||||||
for commit in commits:
|
for commit in commits:
|
||||||
for fileinfo in commit.files:
|
for fileinfo in commit.files:
|
||||||
if request.roottype == 'cvs':
|
if request.roottype == 'cvs':
|
||||||
server_fp.write('cvs update -j %s -j %s %s/%s\n'
|
print 'cvs update -j %s -j %s %s/%s' \
|
||||||
% (fileinfo.rev, prev_rev(fileinfo.rev),
|
% (fileinfo.rev, prev_rev(fileinfo.rev),
|
||||||
fileinfo.dir, fileinfo.file))
|
fileinfo.dir, fileinfo.file)
|
||||||
elif request.roottype == 'svn':
|
elif request.roottype == 'svn':
|
||||||
server_fp.write('svn merge -r %s:%s %s/%s\n'
|
print 'svn merge -r %s:%s %s/%s' \
|
||||||
% (fileinfo.rev, prev_rev(fileinfo.rev),
|
% (fileinfo.rev, prev_rev(fileinfo.rev),
|
||||||
fileinfo.dir, fileinfo.file))
|
fileinfo.dir, fileinfo.file)
|
||||||
|
|
||||||
def view_query(request):
|
def view_query(request):
|
||||||
if not is_query_supported(request):
|
if not is_query_supported(request):
|
||||||
@@ -3455,6 +3363,7 @@ def view_query(request):
|
|||||||
mindate = request.query_dict.get('mindate', '')
|
mindate = request.query_dict.get('mindate', '')
|
||||||
maxdate = request.query_dict.get('maxdate', '')
|
maxdate = request.query_dict.get('maxdate', '')
|
||||||
format = request.query_dict.get('format')
|
format = request.query_dict.get('format')
|
||||||
|
limit = int(request.query_dict.get('limit', 0))
|
||||||
limit_changes = int(request.query_dict.get('limit_changes',
|
limit_changes = int(request.query_dict.get('limit_changes',
|
||||||
request.cfg.options.limit_changes))
|
request.cfg.options.limit_changes))
|
||||||
|
|
||||||
@@ -3521,17 +3430,16 @@ def view_query(request):
|
|||||||
query.SetFromDateObject(mindate)
|
query.SetFromDateObject(mindate)
|
||||||
if maxdate is not None:
|
if maxdate is not None:
|
||||||
query.SetToDateObject(maxdate)
|
query.SetToDateObject(maxdate)
|
||||||
|
if limit:
|
||||||
# Set the admin-defined (via configuration) row limits. This is to avoid
|
query.SetLimit(limit)
|
||||||
# slamming the database server with a monster query.
|
elif format == 'rss':
|
||||||
if format == 'rss':
|
|
||||||
query.SetLimit(request.cfg.cvsdb.rss_row_limit)
|
query.SetLimit(request.cfg.cvsdb.rss_row_limit)
|
||||||
else:
|
|
||||||
query.SetLimit(request.cfg.cvsdb.row_limit)
|
|
||||||
|
|
||||||
# run the query
|
# run the query
|
||||||
db.RunQuery(query)
|
db.RunQuery(query)
|
||||||
|
|
||||||
|
sql = request.server.escape(db.CreateSQLQueryString(query))
|
||||||
|
|
||||||
# gather commits
|
# gather commits
|
||||||
commits = []
|
commits = []
|
||||||
plus_count = 0
|
plus_count = 0
|
||||||
@@ -3543,48 +3451,45 @@ def view_query(request):
|
|||||||
current_desc = query.commit_list[0].GetDescriptionID()
|
current_desc = query.commit_list[0].GetDescriptionID()
|
||||||
current_rev = query.commit_list[0].GetRevision()
|
current_rev = query.commit_list[0].GetRevision()
|
||||||
dir_strip = _path_join(repos_dir)
|
dir_strip = _path_join(repos_dir)
|
||||||
|
|
||||||
for commit in query.commit_list:
|
for commit in query.commit_list:
|
||||||
commit_desc = commit.GetDescriptionID()
|
# base modification time on the newest commit ...
|
||||||
commit_rev = commit.GetRevision()
|
if commit.GetTime() > mod_time: mod_time = commit.GetTime()
|
||||||
|
# form plus/minus totals
|
||||||
# base modification time on the newest commit
|
plus_count = plus_count + int(commit.GetPlusCount())
|
||||||
if commit.GetTime() > mod_time:
|
minus_count = minus_count + int(commit.GetMinusCount())
|
||||||
mod_time = commit.GetTime()
|
# group commits with the same commit message ...
|
||||||
|
desc = commit.GetDescriptionID()
|
||||||
# For CVS, group commits with the same commit message.
|
# For CVS, group commits with the same commit message.
|
||||||
# For Subversion, group them only if they have the same revision number
|
# For Subversion, group them only if they have the same revision number
|
||||||
if request.roottype == 'cvs':
|
if request.roottype == 'cvs':
|
||||||
if current_desc == commit_desc:
|
if current_desc == desc:
|
||||||
|
if not limit_changes or len(files) < limit_changes:
|
||||||
files.append(commit)
|
files.append(commit)
|
||||||
|
else:
|
||||||
|
limited_files = 1
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if current_rev == commit_rev:
|
if current_rev == commit.GetRevision():
|
||||||
|
if not limit_changes or len(files) < limit_changes:
|
||||||
files.append(commit)
|
files.append(commit)
|
||||||
|
else:
|
||||||
|
limited_files = 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# append this grouping
|
# if our current group has any allowed files, append a commit
|
||||||
commit_item = build_commit(request, files, limit_changes,
|
# with those files.
|
||||||
dir_strip, format)
|
if len(files):
|
||||||
if commit_item:
|
commits.append(build_commit(request, files, limited_files, dir_strip))
|
||||||
# update running plus/minus totals
|
|
||||||
plus_count = plus_count + commit_item.plus
|
|
||||||
minus_count = minus_count + commit_item.minus
|
|
||||||
commits.append(commit_item)
|
|
||||||
|
|
||||||
files = [ commit ]
|
files = [ commit ]
|
||||||
limited_files = 0
|
limited_files = 0
|
||||||
current_desc = commit_desc
|
current_desc = desc
|
||||||
current_rev = commit_rev
|
current_rev = commit.GetRevision()
|
||||||
|
|
||||||
# we need to tack on our last commit grouping, if any
|
# we need to tack on our last commit grouping, but, again, only if
|
||||||
commit_item = build_commit(request, files, limit_changes,
|
# it has allowed files.
|
||||||
dir_strip, format)
|
if len(files):
|
||||||
if commit_item:
|
commits.append(build_commit(request, files, limited_files, dir_strip))
|
||||||
# update running plus/minus totals
|
|
||||||
plus_count = plus_count + commit_item.plus
|
|
||||||
minus_count = minus_count + commit_item.minus
|
|
||||||
commits.append(commit_item)
|
|
||||||
|
|
||||||
# only show the branch column if we are querying all branches
|
# only show the branch column if we are querying all branches
|
||||||
# or doing a non-exact branch match on a CVS repository.
|
# or doing a non-exact branch match on a CVS repository.
|
||||||
@@ -3615,7 +3520,7 @@ def view_query(request):
|
|||||||
|
|
||||||
data = common_template_data(request)
|
data = common_template_data(request)
|
||||||
data.update({
|
data.update({
|
||||||
'sql': request.server.escape(db.CreateSQLQueryString(query)),
|
'sql': sql,
|
||||||
'english_query': english_query(request),
|
'english_query': english_query(request),
|
||||||
'queryform_href': queryform_href,
|
'queryform_href': queryform_href,
|
||||||
'backout_href': backout_href,
|
'backout_href': backout_href,
|
||||||
@@ -3629,7 +3534,7 @@ def view_query(request):
|
|||||||
})
|
})
|
||||||
|
|
||||||
if format == 'rss':
|
if format == 'rss':
|
||||||
request.server.header("application/rss+xml")
|
request.server.header("text/xml")
|
||||||
generate_page(request, "rss", data)
|
generate_page(request, "rss", data)
|
||||||
else:
|
else:
|
||||||
request.server.header()
|
request.server.header()
|
||||||
@@ -3659,10 +3564,10 @@ for code, view in _views.items():
|
|||||||
|
|
||||||
def list_roots(cfg):
|
def list_roots(cfg):
|
||||||
allroots = { }
|
allroots = { }
|
||||||
for root in cfg.general.svn_roots.keys():
|
|
||||||
allroots[root] = [cfg.general.svn_roots[root], 'svn']
|
|
||||||
for root in cfg.general.cvs_roots.keys():
|
for root in cfg.general.cvs_roots.keys():
|
||||||
allroots[root] = [cfg.general.cvs_roots[root], 'cvs']
|
allroots[root] = [cfg.general.cvs_roots[root], 'cvs']
|
||||||
|
for root in cfg.general.svn_roots.keys():
|
||||||
|
allroots[root] = [cfg.general.svn_roots[root], 'svn']
|
||||||
return allroots
|
return allroots
|
||||||
|
|
||||||
def load_config(pathname=None, server=None):
|
def load_config(pathname=None, server=None):
|
||||||
@@ -3731,9 +3636,9 @@ def view_error(server, cfg):
|
|||||||
exc_dict = debug.GetExceptionData()
|
exc_dict = debug.GetExceptionData()
|
||||||
status = exc_dict['status']
|
status = exc_dict['status']
|
||||||
if exc_dict['msg']:
|
if exc_dict['msg']:
|
||||||
exc_dict['msg'] = server.escape(exc_dict['msg'])
|
exc_dict['msg'] = htmlify(exc_dict['msg'])
|
||||||
if exc_dict['stacktrace']:
|
if exc_dict['stacktrace']:
|
||||||
exc_dict['stacktrace'] = server.escape(exc_dict['stacktrace'])
|
exc_dict['stacktrace'] = htmlify(exc_dict['stacktrace'])
|
||||||
handled = 0
|
handled = 0
|
||||||
|
|
||||||
# use the configured error template if possible
|
# use the configured error template if possible
|
||||||
@@ -3765,7 +3670,7 @@ def main(server, cfg):
|
|||||||
|
|
||||||
finally:
|
finally:
|
||||||
debug.t_end('main')
|
debug.t_end('main')
|
||||||
debug.t_dump(server.file())
|
debug.dump()
|
||||||
debug.DumpChildren(server)
|
debug.DumpChildren(server)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
53
notes/TODO
53
notes/TODO
@@ -1,53 +0,0 @@
|
|||||||
PREFACE
|
|
||||||
-------
|
|
||||||
This file will go away soon after release 0.8. Please use the SourceForge
|
|
||||||
tracker to resubmit any of the items listed below, if you think, it is
|
|
||||||
still an issue:
|
|
||||||
http://sourceforge.net/tracker/?group_id=18760
|
|
||||||
Before reporting please check, whether someone else has already done this.
|
|
||||||
Working patches increase the chance to be included into the next release.
|
|
||||||
-- PeFu / October 2001
|
|
||||||
|
|
||||||
TODO ITEMS
|
|
||||||
----------
|
|
||||||
*) add Tamminen Eero's comments on how to make Linux directly execute
|
|
||||||
the Python script. From email on Feb 19.
|
|
||||||
[ add other examples, such as my /bin/sh hack or the teeny CGI stub
|
|
||||||
importing the bulk hack ]
|
|
||||||
|
|
||||||
*) insert rcs_path into PATH before calling "rcsdiff". rcsdiff might
|
|
||||||
use "co" and needs to find it on the path.
|
|
||||||
|
|
||||||
*) show the "locked" flag (attach it to the LogEntry objects).
|
|
||||||
Idea from Russell Gordon <russell@hoopscotch.dhs.org>
|
|
||||||
|
|
||||||
*) committing with a specific revision number:
|
|
||||||
http://mailman.lyra.org/pipermail/viewcvs/2000q1/000008.html
|
|
||||||
|
|
||||||
*) add capability similar to cvs2cl.pl:
|
|
||||||
http://mailman.lyra.org/pipermail/viewcvs/2000q2/000050.html
|
|
||||||
suggestion from Chris Meyer <cmeyer@gatan.com>.
|
|
||||||
|
|
||||||
*) add a tree view of the directory structure (and files?)
|
|
||||||
|
|
||||||
*) include a ConfigParser.py to help older Python installations
|
|
||||||
|
|
||||||
*) add a check for the rcs programs/paths to viewvc-install. clarify the
|
|
||||||
dependency on RCS in the docs.
|
|
||||||
|
|
||||||
*) have a "check" mode that verifies binaries are available on rcs_path
|
|
||||||
|
|
||||||
-> alternately (probably?): use rcsparse rather than external tools
|
|
||||||
|
|
||||||
KNOWN BUGS
|
|
||||||
----------
|
|
||||||
*) time.timezone seems to not be available on some 1.5.2 installs.
|
|
||||||
I was unable to verify this. On RedHat and SuSE Linux this bug
|
|
||||||
is non existant.
|
|
||||||
|
|
||||||
*) With old repositories containing many branches, tags or thousands
|
|
||||||
or revisions, the cvsgraph feature becomes unusable (see INSTALL).
|
|
||||||
ViewVC can't do much about this, but it might be possible to
|
|
||||||
investigate the number of branches, tags and revision in advance
|
|
||||||
and disable the cvsgraph links, if the numbers exceed a certain
|
|
||||||
treshold.
|
|
@@ -1,82 +0,0 @@
|
|||||||
RELEASE MANAGEMENT
|
|
||||||
|
|
||||||
ViewVC rolls releases from release branches associate with each minor
|
|
||||||
version of the software. For example, the 1.1.0 is rolled from the
|
|
||||||
1.1.x branch. The same is true for the 1.1.1, 1.1.2, ... releases.
|
|
||||||
|
|
||||||
There is a script, `tools/make-release', which creates a release
|
|
||||||
directory and the various archive files that we distribute. All other
|
|
||||||
steps required to get a ViewVC release out of the door require manual
|
|
||||||
execution (currently by C. Michael Pilato). Those steps are as
|
|
||||||
follows:
|
|
||||||
|
|
||||||
Checkout a working copy of the release branch for the release you
|
|
||||||
intend to roll, and in that working copy, perform the following steps
|
|
||||||
(X, Y, and Z below represent integral major, minor, and patch version
|
|
||||||
numbers, and not literal):
|
|
||||||
|
|
||||||
1. Review any open bug reports:
|
|
||||||
|
|
||||||
http://viewvc.tigris.org/servlets/ProjectIssues
|
|
||||||
|
|
||||||
2. Add a new subsection to the file 'docs/upgrading.html' describing
|
|
||||||
all user visible changes for users of previous releases of ViewVC.
|
|
||||||
Commit any modifications. NOTE: This step should not be necessary
|
|
||||||
for patch releases.
|
|
||||||
|
|
||||||
3. Verify that copyright years are correct in both the LICENSE.html
|
|
||||||
file and the source code.
|
|
||||||
|
|
||||||
4. Update and commit the 'CHANGES' file.
|
|
||||||
|
|
||||||
5. Test, test, test! There is no automatic testsuite available. So
|
|
||||||
just run with permuting different `viewvc.conf' settings... and
|
|
||||||
pray. Fix what needs fixin', keeping the CHANGES file in sync
|
|
||||||
with the branch.
|
|
||||||
|
|
||||||
6. At this point, the source code committed to the release branch
|
|
||||||
should exactly reflect what you wish to distribute and dub "the
|
|
||||||
release".
|
|
||||||
|
|
||||||
7. Edit the file 'lib/viewvc.py' and remove the "-dev" suffix from
|
|
||||||
__version__. The remainder should be of the form "X.Y.Z", where X,
|
|
||||||
Y, and Z are positive integers. Do NOT commit this change.
|
|
||||||
|
|
||||||
8. Update your working copy to HEAD, and tag the release:
|
|
||||||
|
|
||||||
svn up && svn cp -m "Tag the X.Y.Z final release." . ^/tags/X.Y.Z
|
|
||||||
|
|
||||||
9. Go into an empty directory and run the 'make-release' script:
|
|
||||||
|
|
||||||
tools/make-release viewvc-X.Y.Z tags/X.Y.Z
|
|
||||||
|
|
||||||
10. Verify the archive files:
|
|
||||||
|
|
||||||
- do they have a LICENSE.html file?
|
|
||||||
- do they have necessary include documentation?
|
|
||||||
- do they *not* have unnecessary stuff?
|
|
||||||
- do they install and work correctly?
|
|
||||||
|
|
||||||
11. Upload the created archive files (tar.gz and zip) into the Files
|
|
||||||
and Documents section of the Tigris.org project, and modify the
|
|
||||||
CHECKSUMS document there accordingly. Also, drop a copy of the
|
|
||||||
archive files into the root directory of the viewvc.org website
|
|
||||||
(unversioned).
|
|
||||||
|
|
||||||
12. Update the websites (both the viewvc.org/ and www/ ones) to refer
|
|
||||||
to the new release files.
|
|
||||||
|
|
||||||
13. Edit the file 'lib/viewvc.py' again, re-adding the "-dev" suffix
|
|
||||||
and incrementing the patch number assigned to the __version__
|
|
||||||
variable, and commit:
|
|
||||||
|
|
||||||
svn ci -m "Begin a new release cycle."
|
|
||||||
|
|
||||||
14. Edit the Issue Tracker configuration options, adding a new Version
|
|
||||||
for the just-released one, and a new Milestone for the next patch
|
|
||||||
(and possibly, minor or major) release. (For the Milestone sort
|
|
||||||
key, use a packed integer XXYYZZ: 1.0.3 == 10003, 2.11.4 == 21104.)
|
|
||||||
|
|
||||||
15. Send to the announce@ list a message explaining all the cool new
|
|
||||||
features, and post similar announcements to other places interested
|
|
||||||
in this sort of stuff, such as Freshmeat (http://www.freshmeat.net).
|
|
@@ -4,30 +4,22 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="vc_header[is sortby "file"]_sort[end]" colspan="2">
|
<th class="vc_header[is sortby "file"]_sort[end]" colspan="2">
|
||||||
[if-any sortby_file_href]<a href="[sortby_file_href]#dirlist">File</a>[else]File[end]
|
<a href="[sortby_file_href]#dirlist">File
|
||||||
[is sortby "file"]
|
[is sortby "file"]
|
||||||
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
||||||
width="13" height="13"
|
width="13" height="13"
|
||||||
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
||||||
[end]
|
[end]
|
||||||
|
</a>
|
||||||
</th>
|
</th>
|
||||||
[if-any sortby_rev_href]
|
|
||||||
<th class="vc_header[is sortby "rev"]_sort[end]">
|
<th class="vc_header[is sortby "rev"]_sort[end]">
|
||||||
<a href="[sortby_rev_href]#dirlist">Last Change</a>
|
<a href="[sortby_rev_href]#dirlist">Last Change
|
||||||
[is sortby "rev"]
|
[is sortby "rev"]
|
||||||
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
||||||
width="13" height="13"
|
width="13" height="13"
|
||||||
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
||||||
[end]
|
[end]
|
||||||
[else]
|
</a>
|
||||||
<th class="vc_header[is sortby "date"]_sort[end]">
|
|
||||||
[if-any sortby_date_href]<a href="[sortby_date_href]#dirlist">Last Change</a>[else]Last Change[end]
|
|
||||||
[is sortby "date"]
|
|
||||||
<img class="vc_sortarrow" alt="[is sortdir "down"](date)[end]"
|
|
||||||
width="13" height="13"
|
|
||||||
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
|
||||||
[end]
|
|
||||||
[end]
|
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@@ -4,45 +4,50 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="vc_header[is sortby "file"]_sort[end]" colspan="2">
|
<th class="vc_header[is sortby "file"]_sort[end]" colspan="2">
|
||||||
[if-any sortby_file_href]<a href="[sortby_file_href]#dirlist">File</a>[else]File[end]
|
<a href="[sortby_file_href]#dirlist">File
|
||||||
[is sortby "file"]
|
[is sortby "file"]
|
||||||
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
||||||
width="13" height="13"
|
width="13" height="13"
|
||||||
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
||||||
[end]
|
[end]
|
||||||
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th class="vc_header[is sortby "rev"]_sort[end]">
|
<th class="vc_header[is sortby "rev"]_sort[end]">
|
||||||
[if-any sortby_rev_href]<a href="[sortby_rev_href]#dirlist">Rev.</a>[else]Rev.[end]
|
<a href="[sortby_rev_href]#dirlist">Rev.
|
||||||
[is sortby "rev"]
|
[is sortby "rev"]
|
||||||
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
||||||
width="13" height="13"
|
width="13" height="13"
|
||||||
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
||||||
[end]
|
[end]
|
||||||
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th class="vc_header[is sortby "date"]_sort[end]">
|
<th class="vc_header[is sortby "date"]_sort[end]">
|
||||||
[if-any sortby_date_href]<a href="[sortby_date_href]#dirlist">Age</a>[else]Age[end]
|
<a href="[sortby_date_href]#dirlist">Age
|
||||||
[is sortby "date"]
|
[is sortby "date"]
|
||||||
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
||||||
width="13" height="13"
|
width="13" height="13"
|
||||||
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
||||||
[end]
|
[end]
|
||||||
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th class="vc_header[is sortby "author"]_sort[end]">
|
<th class="vc_header[is sortby "author"]_sort[end]">
|
||||||
[if-any sortby_author_href]<a href="[sortby_author_href]#dirlist">Author</a>[else]Author[end]
|
<a href="[sortby_author_href]#dirlist">Author
|
||||||
[is sortby "author"]
|
[is sortby "author"]
|
||||||
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
||||||
width="13" height="13"
|
width="13" height="13"
|
||||||
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
||||||
[end]
|
[end]
|
||||||
|
</a>
|
||||||
</th>
|
</th>
|
||||||
[is cfg.options.show_logs "1"]
|
[is cfg.options.show_logs "1"]
|
||||||
<th class="vc_header[is sortby "log"]_sort[end]">
|
<th class="vc_header[is sortby "log"]_sort[end]">
|
||||||
[if-any sortby_log_href]<a href="[sortby_log_href]#dirlist">Last log entry</a>[else]Last log entry[end]
|
<a href="[sortby_log_href]#dirlist">Last log entry
|
||||||
[is sortby "log"]
|
[is sortby "log"]
|
||||||
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
|
||||||
width="13" height="13"
|
width="13" height="13"
|
||||||
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
|
||||||
[end]
|
[end]
|
||||||
|
</a>
|
||||||
</th>
|
</th>
|
||||||
[end]
|
[end]
|
||||||
</tr>
|
</tr>
|
||||||
|
@@ -9,43 +9,16 @@
|
|||||||
<h3>An Exception Has Occurred</h3>
|
<h3>An Exception Has Occurred</h3>
|
||||||
|
|
||||||
[if-any msg]
|
[if-any msg]
|
||||||
<p>[msg]</p>
|
<p><pre>[msg]</pre></p>
|
||||||
[end]
|
[end]
|
||||||
|
|
||||||
[if-any status]
|
[if-any status]
|
||||||
<h4>HTTP Response Status</h4>
|
<h4>HTTP Response Status</h4>
|
||||||
<p><pre>[status]</pre></p>
|
<p><pre>[status]</pre></p>
|
||||||
<hr />
|
<hr />
|
||||||
[end]
|
[end]
|
||||||
|
|
||||||
[if-any msg][else]
|
|
||||||
<h4>Python Traceback</h4>
|
<h4>Python Traceback</h4>
|
||||||
<p><pre>
|
<p><pre>
|
||||||
[stacktrace]
|
[stacktrace]
|
||||||
</pre></p>
|
</pre></p>
|
||||||
[end]
|
|
||||||
|
|
||||||
[# Here follows a bunch of space characters, present to ensure that
|
|
||||||
our error message is larger than 512 bytes so that IE's "Friendly
|
|
||||||
Error Message" won't show. For more information, see
|
|
||||||
http://oreillynet.com/onjava/blog/2002/09/internet_explorer_subverts_err.html]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -1,24 +1,34 @@
|
|||||||
[if-any search_re_form]
|
[if-any search_re_form]
|
||||||
<hr />
|
<hr />
|
||||||
|
[# this table holds the selectors on the left, and reset on the right ]
|
||||||
|
<table class="auto">
|
||||||
|
<tr>
|
||||||
|
<td>Show files containing the regular expression:</td>
|
||||||
|
<td>
|
||||||
|
<form method="get" action="[search_re_action]">
|
||||||
<div>
|
<div>
|
||||||
Show files containing the regular expression:
|
|
||||||
<form method="get" action="[search_re_action]" style="display: inline;">
|
|
||||||
<div style="display: inline;">
|
|
||||||
[search_re_hidden_values]
|
[search_re_hidden_values]
|
||||||
<input type="text" name="search" value="[search_re]" />
|
<input type="text" name="search" value="[search_re]" />
|
||||||
<input type="submit" value="Show" />
|
<input type="submit" value="Show" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
[if-any search_re]
|
[if-any search_re]
|
||||||
<form method="get" action="[search_re_action]" style="display: inline;">
|
<tr>
|
||||||
<div style="display: inline;">
|
<td> </td>
|
||||||
[search_re_hidden_values]
|
<td>
|
||||||
|
<form method="get" action="[search_tag_action]">
|
||||||
|
<div>
|
||||||
|
[search_tag_hidden_values]
|
||||||
<input type="submit" value="Show all files" />
|
<input type="submit" value="Show all files" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
[end]
|
[end]
|
||||||
|
</table>
|
||||||
[end]
|
[end]
|
||||||
</div>
|
|
||||||
|
|
||||||
[# if you want to disable tarball generation remove the following: ]
|
[# if you want to disable tarball generation remove the following: ]
|
||||||
[if-any tarball_href]
|
[if-any tarball_href]
|
||||||
|
@@ -9,8 +9,8 @@
|
|||||||
<title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [commits.short_log]</title>
|
<title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [commits.short_log]</title>
|
||||||
[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
|
[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
|
||||||
<author>[commits.author]</author>
|
<author>[commits.author]</author>
|
||||||
<pubDate>[if-any commits.rss_date][commits.rss_date][else](unknown date)[end]</pubDate>
|
<pubDate>[commits.rss_date]</pubDate>
|
||||||
<description><pre>[format "xml"][commits.log][end]</pre></description>
|
<description>[commits.log]</description>
|
||||||
</item>[end]
|
</item>[end]
|
||||||
</channel>
|
</channel>
|
||||||
</rss>
|
</rss>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -17,18 +17,17 @@
|
|||||||
|
|
||||||
### Validate input
|
### Validate input
|
||||||
if test $# != 2 && test $# != 1; then
|
if test $# != 2 && test $# != 1; then
|
||||||
echo "Usage: $0 TARGET-DIRECTORY [BRANCH]"
|
echo "Usage: $0 TARGET-DIRECTORY [TAGNAME]"
|
||||||
echo ""
|
echo ""
|
||||||
echo "If BRANCH (i.e. \"tags/1.1.0\" or \"branches/1.0.x\") is not provided,"
|
echo "If TAGNAME is not provided, the release will be rolled from trunk."
|
||||||
echo "the release will be rolled from trunk."
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
TARGET=${1}
|
TARGET=${1}
|
||||||
if test $# = 1; then
|
if test $# == 1; then
|
||||||
ROOT=trunk
|
ROOT=trunk
|
||||||
else
|
else
|
||||||
ROOT=${2}
|
ROOT=tags/${2}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -e ${TARGET}; then
|
if test -e ${TARGET}; then
|
||||||
@@ -37,8 +36,7 @@ if test -e ${TARGET}; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
### Grab an export from the Subversion repository.
|
### Grab an export from the Subversion repository.
|
||||||
EXPORT_URL="http://viewvc.tigris.org/svn/viewvc/${ROOT}"
|
echo "Exporting into:" ${TARGET}
|
||||||
echo "Exporting '${EXPORT_URL}' into '${TARGET}'"
|
|
||||||
|
|
||||||
for PLATFORM in unix windows; do
|
for PLATFORM in unix windows; do
|
||||||
if test ${PLATFORM} = windows; then
|
if test ${PLATFORM} = windows; then
|
||||||
@@ -47,44 +45,30 @@ for PLATFORM in unix windows; do
|
|||||||
EOL="--native-eol LF"
|
EOL="--native-eol LF"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Beginning build for ${PLATFORM}:"
|
svn export ${EOL} http://viewvc.tigris.org/svn/viewvc/${ROOT} ${TARGET}
|
||||||
|
|
||||||
echo " Exporting source code..."
|
|
||||||
svn export --quiet ${EOL} ${EXPORT_URL} ${TARGET}
|
|
||||||
|
|
||||||
### Various shifting, cleanup.
|
### Various shifting, cleanup.
|
||||||
|
|
||||||
|
# Documentation is now also distributed together with the release, but
|
||||||
|
# we still copy the license file to its traditional place (it is small
|
||||||
|
# and many files still contain comments refering to this location):
|
||||||
|
|
||||||
# Remove some not useful directories
|
# Remove some not useful directories
|
||||||
for JUNK in elemx \
|
rm -r ${TARGET}/{elemx,tests,tools,tparse,viewcvs.sourceforge.net,www}
|
||||||
notes \
|
|
||||||
tests \
|
|
||||||
tools \
|
|
||||||
tparse \
|
|
||||||
viewcvs.sourceforge.net \
|
|
||||||
viewvc.org \
|
|
||||||
www; do
|
|
||||||
if [ -d ${TARGET}/${JUNK} ]; then
|
|
||||||
echo " Removing ${TARGET}/${JUNK}..."
|
|
||||||
rm -r ${TARGET}/${JUNK}
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Make sure permissions are reasonable:
|
# Make sure permissions are reasonable:
|
||||||
echo " Normalizing permissions..."
|
|
||||||
find ${TARGET} -print | xargs chmod uoa+r
|
find ${TARGET} -print | xargs chmod uoa+r
|
||||||
find ${TARGET} -type d -print | xargs chmod uoa+x
|
find ${TARGET} -type d -print | xargs chmod uoa+x
|
||||||
|
|
||||||
if test ${PLATFORM} = windows; then
|
if test ${PLATFORM} = windows; then
|
||||||
# Create also a ZIP file for those poor souls :-) still using Windows:
|
# Create also a ZIP file for those poor souls :-) still using Windows:
|
||||||
echo " Creating ZIP archive..."
|
|
||||||
zip -qor9 ${TARGET}.zip ${TARGET}
|
zip -qor9 ${TARGET}.zip ${TARGET}
|
||||||
else
|
else
|
||||||
# Cut the tarball:
|
# Cut the tarball:
|
||||||
echo " Creating tarball archive..."
|
|
||||||
tar cf - ${TARGET} | gzip -9 > ${TARGET}.tar.gz
|
tar cf - ${TARGET} | gzip -9 > ${TARGET}.tar.gz
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# remove target directory
|
# remove target directory
|
||||||
rm -r ${TARGET}
|
rm -r ${TARGET}
|
||||||
done
|
done
|
||||||
echo "Done."
|
echo 'Done.'
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
2
viewcvs.sourceforge.net/.cvsignore
Normal file
2
viewcvs.sourceforge.net/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.tar.gz
|
||||||
|
*.zip
|
1
viewcvs.sourceforge.net/.htaccess
Normal file
1
viewcvs.sourceforge.net/.htaccess
Normal file
@@ -0,0 +1 @@
|
|||||||
|
RedirectMatch ^(.*)$ http://www.viewvc.org/$1
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- Mode: python -*-
|
# -*- Mode: python -*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2012 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -77,7 +77,6 @@ if sys.platform == "win32":
|
|||||||
TREE_LIST = [
|
TREE_LIST = [
|
||||||
("lib", "lib", 0),
|
("lib", "lib", 0),
|
||||||
("templates", "templates", 1),
|
("templates", "templates", 1),
|
||||||
("templates-contrib", "templates-contrib", 1),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@@ -142,9 +142,8 @@ use_rcsparse = 0
|
|||||||
address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address has been configured</a>
|
address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address has been configured</a>
|
||||||
|
|
||||||
#
|
#
|
||||||
# This should contain a list of modules (that is, top-level directories within
|
# This should contain a list of modules in the repository that should not be
|
||||||
# repositories) that should not be displayed (by default or by explicit path
|
# displayed (by default or by explicit path specification).
|
||||||
# specification).
|
|
||||||
#
|
#
|
||||||
# This configuration can be a simple list of modules, or it can get quite
|
# This configuration can be a simple list of modules, or it can get quite
|
||||||
# complex:
|
# complex:
|
||||||
@@ -163,9 +162,8 @@ address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address ha
|
|||||||
#
|
#
|
||||||
# Tests are case-sensitive.
|
# Tests are case-sensitive.
|
||||||
#
|
#
|
||||||
# NOTE: This is for the hiding of modules within repositories, *not*
|
forbidden =
|
||||||
# for the hiding of repositories (roots) themselves.
|
|
||||||
#
|
|
||||||
# Some examples:
|
# Some examples:
|
||||||
#
|
#
|
||||||
# Disallow "example" but allow all others:
|
# Disallow "example" but allow all others:
|
||||||
@@ -186,40 +184,6 @@ address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address ha
|
|||||||
# Allow "xml", forbid other modules starting with "x", and allow the rest:
|
# Allow "xml", forbid other modules starting with "x", and allow the rest:
|
||||||
# forbidden = !xml, x*, !*
|
# forbidden = !xml, x*, !*
|
||||||
#
|
#
|
||||||
forbidden =
|
|
||||||
|
|
||||||
#
|
|
||||||
# This is similar to 'forbidden', but differs in some key ways:
|
|
||||||
#
|
|
||||||
# *) Rather than shell-style "glob" expressions, the values in this
|
|
||||||
# list are regular expressions. You can still prepend a ! character
|
|
||||||
# to each regular expression to invert its meaning, though.
|
|
||||||
#
|
|
||||||
# *) It compares not against modules only, but against paths consisting
|
|
||||||
# of the repository (or root) name plus the path of the versioned file
|
|
||||||
# or directory to be tested. For example, to see if the user is
|
|
||||||
# authorized to see the path "/trunk/www/index.html" in the repository
|
|
||||||
# whose root name is "svnrepos", this authorizer will test the path
|
|
||||||
# "svnrepos/trunk/www/index.html" against the list of forbidden regular
|
|
||||||
# expressions. Directory paths will be terminated by a forward slash.
|
|
||||||
#
|
|
||||||
# NOTE: Use of this configuration option will *disable* any configuration of
|
|
||||||
# the 'forbidden' option -- they cannot be used simultaneously.
|
|
||||||
#
|
|
||||||
# Some examples:
|
|
||||||
#
|
|
||||||
# Disallow files named "PRIVATE", but allow all others:
|
|
||||||
# forbiddenre = /PRIVATE$
|
|
||||||
#
|
|
||||||
# Allow only the "example1" and "example2" roots and the paths inside them,
|
|
||||||
# disallowing all others (which can be done in multiple ways):
|
|
||||||
# forbiddenre = !^example1(/|$), !^example2(/|$)/
|
|
||||||
# forbiddenre = !^example[12](/|$)
|
|
||||||
#
|
|
||||||
# Only allow visibility of HTML files and the directories that hold them:
|
|
||||||
# forbiddenre = !^.*(/|\.html)$
|
|
||||||
#
|
|
||||||
forbiddenre =
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# This option provides a mechanism for custom key/value pairs to be
|
# This option provides a mechanism for custom key/value pairs to be
|
||||||
|
2
viewvc.org/.cvsignore
Normal file
2
viewvc.org/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.tar.gz
|
||||||
|
*.zip
|
68
viewvc.org/contact.html
Normal file
68
viewvc.org/contact.html
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ViewVC: Contact</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="title">
|
||||||
|
<a href="http://www.viewvc.org/"><img
|
||||||
|
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="menu">
|
||||||
|
<p><a href="./index.html">Home</a> |
|
||||||
|
<a href="http://viewvc.tigris.org/">Project Page</a> |
|
||||||
|
<a href="./download.html">Download</a> |
|
||||||
|
<a href="./upgrading.html">Upgrading</a> |
|
||||||
|
<a href="./contributing.html">Contributing</a> |
|
||||||
|
<a href="./license-1.html">License</a> |
|
||||||
|
<a href="./contact.html">Contact</a> |
|
||||||
|
<a href="./who.html">About</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="pagetable">
|
||||||
|
<tr>
|
||||||
|
<td id="pagecolumn1">
|
||||||
|
|
||||||
|
<h4>On this page:</h4>
|
||||||
|
|
||||||
|
<ul id="bookmarks">
|
||||||
|
<li><a href="#sec-contacting-us">Contacting Us</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<address><a href="mailto:users@viewvc.tigris.org">ViewVC Users Group</a></address>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td id="pagecolumn2">
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-contacting-us">Contacting Us</h2>
|
||||||
|
|
||||||
|
<p>Please send any comments, questions, or suggestions to the <a
|
||||||
|
href="mailto:users@viewvc.tigris.org">ViewVC users mailing
|
||||||
|
list</a>. There is also a <a
|
||||||
|
href="mailto:dev@viewvc.tigris.org">mailing list specifically for
|
||||||
|
ViewVC developers</a>. You can subscribe to these lists, as well
|
||||||
|
view the list archives, (and other
|
||||||
|
project lists) <a
|
||||||
|
href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
|
||||||
|
>here</a>.</p>
|
||||||
|
|
||||||
|
<p>ViewVC is an <a href="http://www.opensource.org/">Open
|
||||||
|
Source</a> project, and all <a href="./contributing.html">contributions</a>
|
||||||
|
are welcome.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
276
viewvc.org/contributing.html
Normal file
276
viewvc.org/contributing.html
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ViewVC: Contributing</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="title">
|
||||||
|
<a href="http://www.viewvc.org/"><img
|
||||||
|
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="menu">
|
||||||
|
<p><a href="./index.html">Home</a> |
|
||||||
|
<a href="http://viewvc.tigris.org/">Project Page</a> |
|
||||||
|
<a href="./download.html">Download</a> |
|
||||||
|
<a href="./upgrading.html">Upgrading</a> |
|
||||||
|
<a href="./contributing.html">Contributing</a> |
|
||||||
|
<a href="./license-1.html">License</a> |
|
||||||
|
<a href="./contact.html">Contact</a> |
|
||||||
|
<a href="./who.html">About</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="pagetable">
|
||||||
|
<tr>
|
||||||
|
<td id="pagecolumn1">
|
||||||
|
|
||||||
|
<h4>On this page:</h4>
|
||||||
|
|
||||||
|
<ul id="bookmarks">
|
||||||
|
<li><a href="#sec-getting-started">Getting Started</a></li>
|
||||||
|
<li><a href="#sec-testing">Testing and Reporting</a></li>
|
||||||
|
<li><a href="#sec-coding-style">Coding Style</a></li>
|
||||||
|
<li><a href="#sec-patches">Submitting Patches</a></li>
|
||||||
|
<li><a href="#sec-security">Security</a></li>
|
||||||
|
<li><a href="#sec-adding-features">Adding Features</a></li>
|
||||||
|
<li><a href="#sec-templates">Hacking on Templates</a></li>
|
||||||
|
<li><a href="#sec-releasing">Release Management</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<address><a href="mailto:users@viewvc.tigris.org">ViewVC Users Group</a></address>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td id="pagecolumn2">
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-getting-started">Getting Started</h2>
|
||||||
|
|
||||||
|
<p>Some basic knowledge about <a
|
||||||
|
href="http://www.python.org">Python</a> and development tools like
|
||||||
|
<code>diff</code> is required. Your best bet is to start with a
|
||||||
|
fresh source code snapshot, which you may obtain from our
|
||||||
|
Subversion repository (see instructions <a
|
||||||
|
href="./download.html#sec-subversion">here</a>).</p>
|
||||||
|
|
||||||
|
<p>Version control history can be obtained using Subversion clients,
|
||||||
|
but is also browsable using <a
|
||||||
|
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/"
|
||||||
|
>tigris.org's integrated ViewVC tool</a>.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-testing">Testing and Reporting</h2>
|
||||||
|
|
||||||
|
<p>Testing usability and the installation process on different
|
||||||
|
platforms is also a valuable contribution. Please report your
|
||||||
|
results back to us developers. Bandwidth is getting cheaper daily,
|
||||||
|
so don't be afraid — in fact, feel encouraged — to dump
|
||||||
|
as much detail about the problems you are seeing as possible into
|
||||||
|
your bug reports. Here are some things you definitely should
|
||||||
|
try to include:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>What version of ViewVC you are using (if you are using a source
|
||||||
|
snapshot, tell us the date of that snapshot).</li>
|
||||||
|
|
||||||
|
<li>What operating system your ViewVC is running on.</li>
|
||||||
|
|
||||||
|
<li>What version of Python you are using.</li>
|
||||||
|
|
||||||
|
<li>Whether you are running ViewVC standalone, or as a CGI program
|
||||||
|
under a web server (and if so, what web server).</li>
|
||||||
|
|
||||||
|
<li>The URL of your ViewVC instantiation, if it is public.
|
||||||
|
Sometimes, letting developers see the problem for themselves can
|
||||||
|
save everyone alot of time.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-coding-style">Coding Style</h2>
|
||||||
|
|
||||||
|
<p>Unlike its predecessor, CvsWeb, ViewVC is written in Python, so it
|
||||||
|
doesn't suffer from the "unmaintainable code effect" that hits most
|
||||||
|
Perl projects sooner or later:</p>
|
||||||
|
|
||||||
|
<blockquote><em>"[Perl] combines all the worst aspects of C and Lisp: a
|
||||||
|
billion different sublanguages in one monolithic executable. It
|
||||||
|
combines the power of C with the readability of PostScript."</em>
|
||||||
|
— Jamie Zawinski
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>Of course, a symphony of insanity can be composed in any language,
|
||||||
|
so we do try to stick to some basic guiding principles. Maintain
|
||||||
|
whatever style is present in the code being modified. New code can
|
||||||
|
use anything sane (which generally means <a
|
||||||
|
href="http://python.sourceforge.net/peps/pep-0008.html">PEP 8</a>).
|
||||||
|
Our only real peeve is if someone writes a function call as:
|
||||||
|
<code>some_func (args)</code> — that space between the
|
||||||
|
function name and opening parenthesis is Huge Badness. Oh, and we
|
||||||
|
do <strong>not</strong> use Subversion keywords (such as
|
||||||
|
<code>$</code><code>Id$</code>) within the source.</p>
|
||||||
|
|
||||||
|
<p>Otherwise… <em>shrug</em>.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-patches">Submitting Patches</h2>
|
||||||
|
|
||||||
|
<p>Nothing speaks more loudly when bugs or features are the topic than
|
||||||
|
a patch. And quite frankly, sometimes if you want something done,
|
||||||
|
you gotta do it yourself. So, patches are always welcome. If you
|
||||||
|
aren't sure what exactly a "patch" is, or don't know how
|
||||||
|
to generate one, but you've got code contributions to make, please
|
||||||
|
don't hesitate to ask questions on the mailing lists. Patch
|
||||||
|
generation and application are pretty easy thing to get the hang of,
|
||||||
|
and drastically simplify code submission and review.</p>
|
||||||
|
|
||||||
|
<p>Please use the <a
|
||||||
|
href="http://viewvc.tigris.org/servlets/ProjectIssues">Issue
|
||||||
|
Tracker</a> to submit your patches. Unified contextual diffs
|
||||||
|
against the latest development snapshot are preferred.</p>
|
||||||
|
|
||||||
|
<p>If you have commit access, then you should know what you're doing.
|
||||||
|
Just make changes directly. Subscribing to the <a
|
||||||
|
href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
|
||||||
|
><tt>dev@</tt> developer mailing list</a> is recommended in any
|
||||||
|
case.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-security">Security</h2>
|
||||||
|
|
||||||
|
<p>Since ViewVC is used on the Internet, security is a major concern.
|
||||||
|
If you need to pass data from the request into an external program,
|
||||||
|
please don't use <code>os.system()</code> or
|
||||||
|
<code>os.popen()</code>. Please use the module
|
||||||
|
<code>lib/popen.py</code> that is included in the ViewVC
|
||||||
|
distribution instead.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-adding-features">Adding Features</h2>
|
||||||
|
|
||||||
|
<p>If you need a new configuration option think carefully, into which
|
||||||
|
section it belongs. Try to keep the content of
|
||||||
|
<code>cgi/viewvc.conf.dist</code> file and the library module
|
||||||
|
<code>lib/config.py</code> in sync.</p>
|
||||||
|
|
||||||
|
<p>Because ViewVC is a Web-based application, people will have ViewVC
|
||||||
|
URLs hyperlinked from other sites, embedded in emails, bookmarked
|
||||||
|
in their browsers, etc. It is very important to ensure that those
|
||||||
|
URLs continue to retrieve the information they were intended to
|
||||||
|
retrieve even if ViewVC is upgraded on the hosting server. In
|
||||||
|
other words, as new features require modifications to the <a
|
||||||
|
href="./url-reference.html">ViewVC URL schema</a>, make sure those
|
||||||
|
modifications preserve the existing functionality of all ViewVC
|
||||||
|
URLs.</p>
|
||||||
|
|
||||||
|
<p>The library subdirectory contains a module <code>debug.py</code>,
|
||||||
|
which you may find useful for performance testing.</p>
|
||||||
|
|
||||||
|
<p>If a new file or module is added, a new line in the installer
|
||||||
|
program <code>viewvc-install</code> is required.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-templates">Hacking on Templates</h2>
|
||||||
|
|
||||||
|
<p>The library module <code>ezt.py</code> contains a module docstring
|
||||||
|
which describes the directives used in the HTML templates used by
|
||||||
|
ViewVC. The templates themselves can be found in the
|
||||||
|
<code>templates</code> subdirectory. We're currently developing a
|
||||||
|
how-to guide for <a href="./template-authoring-guide.html">ViewVC
|
||||||
|
template customization</a>.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-releasing">Release Management</h2>
|
||||||
|
|
||||||
|
<p>There is a script, <code>tools/make-release</code>, which creates a
|
||||||
|
release directory and the various archive files that we distribute.
|
||||||
|
All other steps required to get a ViewVC release out of the door
|
||||||
|
require manual execution (currently by C. Michael Pilato). Those
|
||||||
|
steps are as follows:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
|
||||||
|
<li>Add a new subsection to the file
|
||||||
|
<code>website/upgrading.html</code> describing all user visible
|
||||||
|
changes for users of previous releases of ViewVC.</li>
|
||||||
|
|
||||||
|
<li>Update the <code>CHANGES</code> file</li>
|
||||||
|
|
||||||
|
<li>Update the <code>website/index.html</code> file to refer to the
|
||||||
|
new X.Y files. (there are three links to update)</li>
|
||||||
|
|
||||||
|
<li>Edit the file <code>lib/viewvc.py</code> and remove the
|
||||||
|
<tt>"-dev"</tt> suffix from <code>__version__</code>. The
|
||||||
|
remainder should be of the form X.Y.Z, where X, Y, and Z are
|
||||||
|
positive integers.</li>
|
||||||
|
|
||||||
|
<li>Ensure all of the above changes have been committed.</li>
|
||||||
|
|
||||||
|
<li>Test, Test, Test! At the time of this writing (1.0-dev) there
|
||||||
|
is no automatic testsuite available. So just run with
|
||||||
|
permuting different <code>viewvc.conf</code> settings…
|
||||||
|
and pray.</li>
|
||||||
|
|
||||||
|
<li>Review any open <a
|
||||||
|
href="http://viewvc.tigris.org/servlets/ProjectIssues">bug
|
||||||
|
reports.</a></li>
|
||||||
|
|
||||||
|
<li>Use <code>svn cp</code> to tag the release to
|
||||||
|
<code>/tags/<i>X</i>.<i>Y</i>.<i>Z</i></code>, where
|
||||||
|
<i>X</i>, <i>Y</i>, and <i>Z</i> should be replaced by the
|
||||||
|
release number from above. If a developer is willing to
|
||||||
|
volunteer as a bug fix patch release manager, it is now
|
||||||
|
possible to start here at this point with a feature-frozen
|
||||||
|
branch using <code>svn cp</code> to copy the tag to
|
||||||
|
<code>/branches/<i>X</i>.<i>Y</i>.x</code>.</li>
|
||||||
|
|
||||||
|
<li>Go into an empty directory and run <code>tools/make-release
|
||||||
|
viewvc-<i>X.Y.Z</i> <i>X.Y.Z</i></code>. This step requires
|
||||||
|
read access to the Subversion source code repository.</li>
|
||||||
|
|
||||||
|
<li>Upload the created archive files (tar.gz and zip) into the
|
||||||
|
Files and Documents section of the Tigris.org project.</li>
|
||||||
|
|
||||||
|
<li>Edit the file <code>lib/viewvc.py</code> again and this time
|
||||||
|
increment the <code>__version__</code> for the next release
|
||||||
|
cycle, again append the <code>-dev</code> to the version and
|
||||||
|
again <code>svn commit -m "Begin a new release cycle."
|
||||||
|
lib/viewvc.py</code>.</li>
|
||||||
|
|
||||||
|
<li>Write an announcement explaining all the cool new features and
|
||||||
|
post it <a
|
||||||
|
href="mailto:announce@viewvc.tigris.org">announce@viewvc.tigris.org</a>,
|
||||||
|
to the project's News area, and to other places interested in
|
||||||
|
this sort of stuff (such as <a
|
||||||
|
href="http://www.freshmeat.net">Freshmeat</a>).</p>
|
||||||
|
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
79
viewvc.org/download.html
Normal file
79
viewvc.org/download.html
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ViewVC: Download</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="title">
|
||||||
|
<a href="http://www.viewvc.org/"><img
|
||||||
|
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="menu">
|
||||||
|
<p><a href="./index.html">Home</a> |
|
||||||
|
<a href="http://viewvc.tigris.org/">Project Page</a> |
|
||||||
|
<a href="./download.html">Download</a> |
|
||||||
|
<a href="./upgrading.html">Upgrading</a> |
|
||||||
|
<a href="./contributing.html">Contributing</a> |
|
||||||
|
<a href="./license-1.html">License</a> |
|
||||||
|
<a href="./contact.html">Contact</a> |
|
||||||
|
<a href="./who.html">About</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="pagetable">
|
||||||
|
<tr>
|
||||||
|
<td id="pagecolumn1">
|
||||||
|
|
||||||
|
<h4>On this page:</h4>
|
||||||
|
|
||||||
|
<ul id="bookmarks">
|
||||||
|
<li><a href="#sec-download">Downloading</a></li>
|
||||||
|
<li><a href="#sec-subversion">Subversion</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<address><a href="mailto:users@viewvc.tigris.org">ViewVC Users Group</a></address>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td id="pagecolumn2">
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-download">Downloading</h2>
|
||||||
|
|
||||||
|
<p>You can download the ViewVC (and the older ViewCVS releases, too)
|
||||||
|
from our <a
|
||||||
|
href="http://viewvc.tigris.org/servlets/ProjectDocumentList?folderID=6004"
|
||||||
|
>File and Documents</a> area. For information about what has
|
||||||
|
changed in each release, see the <a
|
||||||
|
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/CHANGES?rev=HEAD"
|
||||||
|
>CHANGES</a> file.</p>
|
||||||
|
|
||||||
|
<p>We are also making <a href="./nightly/">nightly snapshots</a>
|
||||||
|
available in tar.gz and zip formats.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-subversion">Subversion</h2>
|
||||||
|
|
||||||
|
<p>The source code for ViewVC is maintained in a Subversion repository
|
||||||
|
at Tigris.org. You can checkout the trunk of our development tree
|
||||||
|
from <a href="http://viewvc.tigris.org/svn/viewvc/trunk/"
|
||||||
|
><tt>http://viewvc.tigris.org/svn/viewvc/trunk/</tt></a>. You'll
|
||||||
|
need to provide your Tigris.org username and password when so
|
||||||
|
prompted, or, if you don't have a Tigris.org account, use "guest"
|
||||||
|
as both the username and password.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
viewvc.org/images/bg-grad.jpg
Normal file
BIN
viewvc.org/images/bg-grad.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
viewvc.org/images/title.jpg
Normal file
BIN
viewvc.org/images/title.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
viewvc.org/images/title.xcf
Normal file
BIN
viewvc.org/images/title.xcf
Normal file
Binary file not shown.
192
viewvc.org/index.html
Normal file
192
viewvc.org/index.html
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ViewVC: Repository Browsing</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="title">
|
||||||
|
<a href="http://www.viewvc.org/"><img
|
||||||
|
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="menu">
|
||||||
|
<p><a href="./index.html">Home</a> |
|
||||||
|
<a href="http://viewvc.tigris.org/">Project Page</a> |
|
||||||
|
<a href="./download.html">Download</a> |
|
||||||
|
<a href="./upgrading.html">Upgrading</a> |
|
||||||
|
<a href="./contributing.html">Contributing</a> |
|
||||||
|
<a href="./license-1.html">License</a> |
|
||||||
|
<a href="./contact.html">Contact</a> |
|
||||||
|
<a href="./who.html">About</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="pagetable">
|
||||||
|
<tr>
|
||||||
|
<td id="pagecolumn1">
|
||||||
|
|
||||||
|
<h4>On this page:</h4>
|
||||||
|
|
||||||
|
<ul id="bookmarks">
|
||||||
|
<li><a href="#sec-what-is-viewvc">What Is ViewVC?</a></li>
|
||||||
|
<li><a href="#sec-requirements">Requirements</a></li>
|
||||||
|
<li><a href="#sec-future">Future Plans</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<address><a href="mailto:users@viewvc.tigris.org">ViewVC Users Group</a></address>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td id="pagecolumn2">
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-what-is-viewvc">What Is ViewVC?</h2>
|
||||||
|
|
||||||
|
<p>ViewVC is a browser interface for CVS and Subversion version
|
||||||
|
control repositories. It generates templatized HTML to present
|
||||||
|
navigable directory, revision, and change log listings. It can
|
||||||
|
display specific versions of files as well as diffs between those
|
||||||
|
versions. Basically, ViewVC provides the bulk of the report-like
|
||||||
|
functionality you expect out of your version control tool, but much
|
||||||
|
more prettily than the average textual command-line program
|
||||||
|
output.</p>
|
||||||
|
|
||||||
|
<p>Here are some of the additional features of ViewVC:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>Support for filesystem-accessible CVS and Subversion repositories.</li>
|
||||||
|
|
||||||
|
<li>Individually configurable virtual host support.</li>
|
||||||
|
|
||||||
|
<li>Line-based annotation/blame display.</li>
|
||||||
|
|
||||||
|
<li>Revision graph capabilities (via integration with <a
|
||||||
|
href="http://www.akhphd.au.dk/~bertho/cvsgraph/">CvsGraph</a>)
|
||||||
|
(<em>CVS only</em>).</li>
|
||||||
|
|
||||||
|
<li>Syntax highlighting support (via integration with <a
|
||||||
|
href="http://www.codento.com/people/mtr/genscript/">GNU
|
||||||
|
enscript</a> or
|
||||||
|
<a href="http://www.andre-simon.de/">Highlight</a>).</li>
|
||||||
|
|
||||||
|
<li><a href="http://www.mozilla.org/projects/bonsai/">Bonsai</a>-like
|
||||||
|
repository query facilities.</li>
|
||||||
|
|
||||||
|
<li>Template-driven output generation.</li>
|
||||||
|
|
||||||
|
<li>Colorized, side-by-side differences.</li>
|
||||||
|
|
||||||
|
<li>Tarball generation (by tag/branch for CVS, by revision for
|
||||||
|
Subversion).</li>
|
||||||
|
|
||||||
|
<li>I18N support based on the Accept-Language request header.</li>
|
||||||
|
|
||||||
|
<li>Ability to run either as CGI script or as a standalone
|
||||||
|
server.</li>
|
||||||
|
|
||||||
|
<li>Regexp-based file searching.</li>
|
||||||
|
|
||||||
|
<li>INI-like configuration file (as opposed to requiring actual code
|
||||||
|
tweaks).</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>For a complete list of changes present in each release, see
|
||||||
|
ViewVC's <a
|
||||||
|
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/CHANGES?rev=HEAD"
|
||||||
|
>CHANGES</a> file.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-requirements">Requirements</h2>
|
||||||
|
|
||||||
|
<p>The only hard software requirement for running ViewVC is <a
|
||||||
|
href="http://www.python.org/">Python 1.5.2</a> or later. All other
|
||||||
|
requirements depend on what you want to do with the tool.</p>
|
||||||
|
|
||||||
|
<p>If you plan to use ViewVC with CVS repositories, you need the
|
||||||
|
following things:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="http://www.cs.purdue.edu/homes/trinkle/RCS/">RCS</a>
|
||||||
|
(Revision Control System)</li>
|
||||||
|
|
||||||
|
<li><a href="http://www.gnu.org/software/diffutils/diffutils.html">GNU
|
||||||
|
diff</a></li>
|
||||||
|
|
||||||
|
<li>Read-only, physical access to a CVS repository.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>For use with Subversion repositories, you need these things:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="http://subversion.tigris.org/">Subversion</a> 1.2 or
|
||||||
|
later and its SWIG Python bindings.</li>
|
||||||
|
|
||||||
|
<li><a href="http://www.gnu.org/software/diffutils/diffutils.html">GNU
|
||||||
|
diff</a></li>
|
||||||
|
|
||||||
|
<li>Physical access to a Subversion repository (though there is
|
||||||
|
limited, use-at-your-risk support for remote access, too).</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>ViewVC integrates with additional pieces of software to provide
|
||||||
|
certain bits of optional functionality:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="http://www.mysql.com/">MySQL</a> — Needed to use
|
||||||
|
the commit database query functionality.</li>
|
||||||
|
|
||||||
|
<li><a href="http://www.codento.com/people/mtr/genscript/">GNU
|
||||||
|
enscript</a> — Needed for syntax highlighting in versioned
|
||||||
|
file contents displays</li>
|
||||||
|
|
||||||
|
<li><a href="http://www.akhphd.au.dk/~bertho/cvsgraph/">CvsGraph</a>
|
||||||
|
— Needed for version graph displays.</li>
|
||||||
|
|
||||||
|
<li><a href="http://httpd.apache.org/">Apache HTTP Server</a>, or
|
||||||
|
another server capable of running CGI programs — unless
|
||||||
|
you just want ViewVC to run in standalone server mode.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-future">Future Plans</h2>
|
||||||
|
|
||||||
|
<p>ViewVC is an Open Source project. So any future development
|
||||||
|
depends on the <a href="./contributing.html">contributions</a> that
|
||||||
|
will be made by its user community. Certainly working patches have
|
||||||
|
a greater chance to become realized quickly than feature requests,
|
||||||
|
but please don't hesitate to submit your suggestions to our <a
|
||||||
|
href="http://viewvc.tigris.org/servlets/ProjectIssues">issue
|
||||||
|
tracker</a>.</p>
|
||||||
|
|
||||||
|
<p>Some things we're thinking about include:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>UI streamlining/simplification.</li>
|
||||||
|
<li>Integration with CVS and Subversion commit mail scripts.</li>
|
||||||
|
<li>Integration with an indexer such as LXR.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -1,21 +1,63 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>ViewVC: License v1</title>
|
<title>ViewVC: License v1</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<div id="title">
|
||||||
|
<a href="http://www.viewvc.org/"><img
|
||||||
|
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="menu">
|
||||||
|
<p><a href="./index.html">Home</a> |
|
||||||
|
<a href="http://viewvc.tigris.org/">Project Page</a> |
|
||||||
|
<a href="./download.html">Download</a> |
|
||||||
|
<a href="./upgrading.html">Upgrading</a> |
|
||||||
|
<a href="./contributing.html">Contributing</a> |
|
||||||
|
<a href="./license-1.html">License</a> |
|
||||||
|
<a href="./contact.html">Contact</a> |
|
||||||
|
<a href="./who.html">About</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="pagetable">
|
||||||
|
<tr>
|
||||||
|
<td id="pagecolumn1">
|
||||||
|
|
||||||
|
<h4>On this page:</h4>
|
||||||
|
|
||||||
|
<ul id="bookmarks">
|
||||||
|
<li><a href="#sec-license">License</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<address><a href="mailto:users@viewvc.tigris.org">ViewVC Users Group</a></address>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td id="pagecolumn2">
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2 id="sec-license">License</h2>
|
||||||
|
|
||||||
<p>The following text constitutes the license agreement for the <a
|
<p>The following text constitutes the license agreement for the <a
|
||||||
href="http://www.viewvc.org/">ViewVC</a> software (formerly known
|
href="./index.html">ViewVC</a> software (formerly known as
|
||||||
as ViewCVS). It is an agreement between <a
|
ViewCVS). It is an agreement between <a
|
||||||
href="http://www.viewvc.org/who.html#sec-viewcvs-group">The ViewCVS
|
href="./who.html#sec-viewcvs-group">The ViewCVS Group</a> and the
|
||||||
Group</a> and the users of ViewVC.</p>
|
users of ViewVC.</p>
|
||||||
|
|
||||||
<blockquote>
|
<p style="font-size: 80%;"><em>Note: the copyright years were updated
|
||||||
|
on May 12, 2001 and September 5, 2002. No other changes were made
|
||||||
|
to the license.</em></p>
|
||||||
|
|
||||||
<p><strong>Copyright © 1999-2012 The ViewCVS Group. All rights
|
<hr/>
|
||||||
|
|
||||||
|
<p><strong>Copyright © 1999-2002 The ViewCVS Group. All rights
|
||||||
reserved.</strong></p>
|
reserved.</strong></p>
|
||||||
|
|
||||||
<p>By using ViewVC, you agree to the terms and conditions set forth
|
<p>By using ViewVC, you agree to the terms and conditions set forth
|
||||||
@@ -48,21 +90,10 @@
|
|||||||
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
SUCH DAMAGE.</p>
|
SUCH DAMAGE.</p>
|
||||||
|
|
||||||
</blockquote>
|
</div>
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<p>The following changes have occured to this license over time:</p>
|
|
||||||
<ul>
|
|
||||||
<li>May 12, 2001 — copyright years updated</li>
|
|
||||||
<li>September 5, 2002 — copyright years updated</li>
|
|
||||||
<li>March 17, 2006 — software renamed from "ViewCVS"</li>
|
|
||||||
<li>April 10, 2007 — copyright years updated</li>
|
|
||||||
<li>February 22, 2008 — copyright years updated</li>
|
|
||||||
<li>March 29, 2010 — copyright years updated</li>
|
|
||||||
<li>February 18, 2011 — copyright years updated</li>
|
|
||||||
<li>January 23, 2012 — copyright years updated</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
151
viewvc.org/styles.css
Normal file
151
viewvc.org/styles.css
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
body {
|
||||||
|
background-color: rgb(180,193,205);
|
||||||
|
background-image: url('./images/bg-grad.jpg');
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
color: black;
|
||||||
|
font-family: arial, sans-serif;
|
||||||
|
font-size: 90%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
background-color: rgb(100,128,150);
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 95%;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
address {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 60%;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
background-color: rgb(204,213,221);
|
||||||
|
padding: 2px 0.5em 2px 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
border-bottom: dotted 1px rgb(180,193,205);
|
||||||
|
font-size: 110%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
padding: 2px 0.5em 2px 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
padding: 2px 0.5em 2px 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 90%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, dl, ul, ol {
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, ol {
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 0 0 0 0.25in;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-size: 105%;
|
||||||
|
font-style: italic;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 0 0.25in 0 0.25in;
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
background: white;
|
||||||
|
border-color: rgb(24,24,24);
|
||||||
|
border-width: 1px 2px 2px 1px;
|
||||||
|
border-style: solid;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu {
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu a, #menu a:visited {
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu a:hover {
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#submenu {
|
||||||
|
background: rgb(90%,97%,99%);
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagetable tr {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagetable {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagecolumn1 {
|
||||||
|
width: 175px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagecolumn1 a, #pagecolumn1 a:visited {
|
||||||
|
color: rgb(0,0,164);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagecolumn1 a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagecolumn2 {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagecolumn2 a, #pagecolumn2 a:visited {
|
||||||
|
color: rgb(0,0,164);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagecolumn2 a:hover {
|
||||||
|
background-color: rgb(180,193,205);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bookmarks {
|
||||||
|
padding-left: 0.25in;
|
||||||
|
font-size: 80%;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
@@ -1586,20 +1586,10 @@ td {
|
|||||||
<td>Boolean</td>
|
<td>Boolean</td>
|
||||||
<td>True if files list was cut short due to <tt>limit_changes</tt>.</td>
|
<td>True if files list was cut short due to <tt>limit_changes</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="varlevel2">
|
|
||||||
<td class="varname">commits.minus</td>
|
|
||||||
<td>String</td>
|
|
||||||
<td>Total number of lines removed from files in this commit.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">commits.num_files</td>
|
<td class="varname">commits.num_files</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>Total number of files in the <var>commits.files</var> list.</td>
|
<td>Number of files in the <var>commits.files</var> list.</td>
|
||||||
</tr>
|
|
||||||
<tr class="varlevel2">
|
|
||||||
<td class="varname">commits.plus</td>
|
|
||||||
<td>String</td>
|
|
||||||
<td>Number of lines added to files in this commit.</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">commits.rev</td>
|
<td class="varname">commits.rev</td>
|
||||||
@@ -1640,14 +1630,12 @@ td {
|
|||||||
<tr class="varlevel1">
|
<tr class="varlevel1">
|
||||||
<td class="varname">minus_count</td>
|
<td class="varname">minus_count</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>Total number of lines removed from all files across all returned
|
<td>Total number of lines removed in the commit (over all files).</td>
|
||||||
commits.</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="varlevel1">
|
<tr class="varlevel1">
|
||||||
<td class="varname">plus_count</td>
|
<td class="varname">plus_count</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>Total number of lines added to all files across all returned
|
<td>Total number of lines added in the commit (over all files).</td>
|
||||||
commits.</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="varlevel1">
|
<tr class="varlevel1">
|
||||||
<td class="varname">queryform_href</td>
|
<td class="varname">queryform_href</td>
|
@@ -89,7 +89,7 @@ th.caption {
|
|||||||
<li><a href="#compat-tarball">'<code>tarball=1</code>' Parameter ⇒ '<code>view=tar</code>'</a></li>
|
<li><a href="#compat-tarball">'<code>tarball=1</code>' Parameter ⇒ '<code>view=tar</code>'</a></li>
|
||||||
<li><a href="#compat-graph">'<code>graph=1</code>' Parameter ⇒ '<code>view=graph</code>'</a></li>
|
<li><a href="#compat-graph">'<code>graph=1</code>' Parameter ⇒ '<code>view=graph</code>'</a></li>
|
||||||
<li><a href="#compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters ⇒ '<code>view=graphimg</code>'</a></li>
|
<li><a href="#compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters ⇒ '<code>view=graphimg</code>'</a></li>
|
||||||
<li><a href="#compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters⇒ '<code>view=markup</code>'
|
<li><a href="#compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters⇒ '<code>view=markup</code>'
|
||||||
<li><a href="#compat-attic">'<code>Attic/FILE</code>' Paths ⇒ '<code>FILE</code>'</a></li>
|
<li><a href="#compat-attic">'<code>Attic/FILE</code>' Paths ⇒ '<code>FILE</code>'</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -284,6 +284,11 @@ th.caption {
|
|||||||
<td>depends</td>
|
<td>depends</td>
|
||||||
<td><a href="#view-param"><code>view</code> parameter</a>, not needed if the <code>default_file_view</code> configuration variable is set to <code>co</code>, since that makes the checkout view the default view for file paths. Also not needed if the <code>/*checkout*</code> magic prefix or the <code>revision</code> parameter is present.
|
<td><a href="#view-param"><code>view</code> parameter</a>, not needed if the <code>default_file_view</code> configuration variable is set to <code>co</code>, since that makes the checkout view the default view for file paths. Also not needed if the <code>/*checkout*</code> magic prefix or the <code>revision</code> parameter is present.
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>content-type=<var>TYPE</var></code></td>
|
||||||
|
<td>optional</td>
|
||||||
|
<td>MIME type to send with checked out file, default is a guess based on file extension</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>revision=<var>REVISION</var></code></td>
|
<td><code>revision=<var>REVISION</var></code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
@@ -867,7 +872,7 @@ th.caption {
|
|||||||
<td>file query string</td>
|
<td>file query string</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>file_match=<var>FILE_MATCH</var></code></td>
|
<td><code>file_match=FILE_MATCH</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type of file match</td>
|
<td>"exact" "like" "glob" "regex" or "notregex" determining type of file match</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -877,37 +882,37 @@ th.caption {
|
|||||||
<td>author query string</td>
|
<td>author query string</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>who_match=<var>WHO_MATCH</var></code></td>
|
<td><code>who_match=WHO_MATCH</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type of author match</td>
|
<td>"exact" "like" "glob" "regex" or "notregex" determining type of author match</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>querysort=<var>SORT</var></code></td>
|
<td><code>querysort=SORT</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"date" "author" or "file" determining order of query results</td>
|
<td>"date" "author" or "file" determining order of query results</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>date=<var>DATE</var></code></td>
|
<td><code>date=DATE</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"hours" "day" "week" "month" "all" or "explicit" to filter query results by date</td>
|
<td>"hours" "day" "week" "month" "all" or "explicit" to filter query results by date</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>hours=<var>HOURS</var></code></td>
|
<td><code>hours=HOURS</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>number of hours back to include results from when <code><var>DATE</var></code> is "hours"</td>
|
<td>number of hours back to include results from when <code><var>DATE</var></code> is "hours"</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>mindate=<var>MINDATE</var></code></td>
|
<td><code>mindate=MINDATE</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>earliest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
|
<td>earliest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>maxdate=<var>MAXDATE</var></code></td>
|
<td><code>maxdate=MAXDATE</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>latest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
|
<td>latest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
|
<td><code>limit_changes=LIMIT_CHANGES</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>maximum number of files to list per commit in query results. Default is value of <code>limit_changes</code> configuration option</td>
|
<td>maximum number of files to list per commit in query results. Default is value of <code>limit_changes</code> configuration option</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -965,7 +970,7 @@ th.caption {
|
|||||||
<td>branch query string</td>
|
<td>branch query string</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>branch_match=<var>BRANCH_MATCH</var></code></td>
|
<td><code>branch_match=BRANCH_MATCH</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type of branch match</td>
|
<td>"exact" "like" "glob" "regex" or "notregex" determining type of branch match</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -980,7 +985,7 @@ th.caption {
|
|||||||
<td>file query string</td>
|
<td>file query string</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>file_match=<var>FILE_MATCH</var></code></td>
|
<td><code>file_match=FILE_MATCH</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type of file match</td>
|
<td>"exact" "like" "glob" "regex" or "notregex" determining type of file match</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -990,42 +995,47 @@ th.caption {
|
|||||||
<td>author query string</td>
|
<td>author query string</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>who_match=<var>WHO_MATCH</var></code></td>
|
<td><code>who_match=WHO_MATCH</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type of author match</td>
|
<td>"exact" "like" "glob" "regex" or "notregex" determining type of author match</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>querysort=<var>SORT</var></code></td>
|
<td><code>querysort=SORT</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"date" "author" or "file" determining order of query results</td>
|
<td>"date" "author" or "file" determining order of query results</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>date=<var>DATE</var></code></td>
|
<td><code>date=DATE</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"hours" "day" "week" "month" "all" or "explicit" to filter query results by date</td>
|
<td>"hours" "day" "week" "month" "all" or "explicit" to filter query results by date</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>hours=<var>HOURS</var></code></td>
|
<td><code>hours=HOURS</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>number of hours back to include results from when <code><var>DATE</var></code> is "hours"</td>
|
<td>number of hours back to include results from when <code><var>DATE</var></code> is "hours"</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>mindate=<var>MINDATE</var></code></td>
|
<td><code>mindate=MINDATE</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>earliest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
|
<td>earliest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>maxdate=<var>MAXDATE</var></code></td>
|
<td><code>maxdate=MAXDATE</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>latest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
|
<td>latest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>format=<var>FORMAT</var></code></td>
|
<td><code>format=FORMAT</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>"rss" or "backout" values to generate an rss feed or list of commands to back out changes instead showing a normal query result page</td>
|
<td>"rss" or "backout" values to generate an rss feed or list of commands to back out changes instead showing a normal query result page</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
|
<td><code>limit=LIMIT</code></td>
|
||||||
|
<td>optional</td>
|
||||||
|
<td>maximum number of file-revisions to process during a query. Default is value of <code>row_limit</code> configuration option</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>limit_changes=LIMIT_CHANGES</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>maximum number of files to list per commit in query results. Default is value of <code>limit_changes</code> configuration option</td>
|
<td>maximum number of files to list per commit in query results. Default is value of <code>limit_changes</code> configuration option</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -1077,7 +1087,7 @@ th.caption {
|
|||||||
<td><a href="#revision-param"><code>revision</code> parameter</a></td>
|
<td><a href="#revision-param"><code>revision</code> parameter</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
|
<td><code>limit_changes=LIMIT_CHANGES</code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
<td>maximum number of files to list per commit. Default is value of <code>limit_changes</code> configuration option</td>
|
<td>maximum number of files to list per commit. Default is value of <code>limit_changes</code> configuration option</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -1223,8 +1233,8 @@ th.caption {
|
|||||||
<h3 id="compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters ⇒ '<code>view=graphimg</code>'</h3>
|
<h3 id="compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters ⇒ '<code>view=graphimg</code>'</h3>
|
||||||
<p>A <code>graph=1&makeimage=1</code> parameter is treated like a <code>view=graph</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
|
<p>A <code>graph=1&makeimage=1</code> parameter is treated like a <code>view=graph</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
|
||||||
|
|
||||||
<h3 id="compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters⇒ '<code>view=markup</code>'; other values ignored</h3>
|
<h3 id="compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters⇒ '<code>view=markup</code>'</h3>
|
||||||
<p><code>content-type=text/vnd.viewcvs-markup</code> and <code>content-type=text/x-cvsweb-markup</code> parameters are treated like a <code>view=markup</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future. Other values of the <code>content-type</code> parameter, which were used to dictate the MIME type of files displayed in the checkout/download view prior to ViewVC 1.0.6, are ignored.</p>
|
<p><code>content_type=text/vnd.viewcvs-markup</code> and <code>content_type=text/x-cvsweb-markup</code> parameters are treated like a <code>view=markup</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
|
||||||
|
|
||||||
<h3 id="compat-attic">'<code>Attic/FILE</code>' Paths ⇒ '<code>FILE</code>'</h3>
|
<h3 id="compat-attic">'<code>Attic/FILE</code>' Paths ⇒ '<code>FILE</code>'</h3>
|
||||||
<p>When ViewVC encounters an invalid repository path whose last or second-to-last component is named <code>Attic</code>, and stripping the component yields a valid path, it will redirect to a URL with that path.</p>
|
<p>When ViewVC encounters an invalid repository path whose last or second-to-last component is named <code>Attic</code>, and stripping the component yields a valid path, it will redirect to a URL with that path.</p>
|
159
viewvc.org/who.html
Normal file
159
viewvc.org/who.html
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ViewVC: About</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="title">
|
||||||
|
<a href="http://www.viewvc.org/"><img
|
||||||
|
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="menu">
|
||||||
|
<p><a href="./index.html">Home</a> |
|
||||||
|
<a href="http://viewvc.tigris.org/">Project Page</a> |
|
||||||
|
<a href="./download.html">Download</a> |
|
||||||
|
<a href="./upgrading.html">Upgrading</a> |
|
||||||
|
<a href="./contributing.html">Contributing</a> |
|
||||||
|
<a href="./license-1.html">License</a> |
|
||||||
|
<a href="./contact.html">Contact</a> |
|
||||||
|
<a href="./who.html">About</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="pagetable">
|
||||||
|
<tr>
|
||||||
|
<td id="pagecolumn1">
|
||||||
|
|
||||||
|
<h4>On this page:</h4>
|
||||||
|
|
||||||
|
<ul id="bookmarks">
|
||||||
|
<li><a href="#sec-history">The History of ViewVC</a></li>
|
||||||
|
<li><a href="#sec-viewcvs-group">The ViewCVS Group</a></li>
|
||||||
|
<li><a href="#sec-site-credits">About This Site</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<address><a href="mailto:users@viewvc.tigris.org">ViewVC Users Group</a></address>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td id="pagecolumn2">
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2 id="sec-history">The History of ViewVC</h2>
|
||||||
|
|
||||||
|
<p>The ViewVC software was inspired by <a
|
||||||
|
href="http://people.freebsd.org/~fenner/cvsweb/">cvsweb</a>
|
||||||
|
(originally written by Bill Fenner and then further developed by <a
|
||||||
|
href="mailto:zeller@think.de">Henner Zeller</a>). Greg Stein
|
||||||
|
wanted to make some changes and updates, but cvsweb was implemented
|
||||||
|
in Perl. He wrote:</p>
|
||||||
|
|
||||||
|
<blockquote style="font-style: italic;">"While I can manage some
|
||||||
|
Perl, cvsweb was rather unmaintainable for me. So I undertook the
|
||||||
|
task to convert the software to Python. As a result, I've actually
|
||||||
|
been able to go <em>way</em> beyond the simple changes that I had
|
||||||
|
envisioned."</blockquote>
|
||||||
|
|
||||||
|
<p>So ViewVC started out as just a port of the cvsweb script,
|
||||||
|
originally called ViewCVS. Along the way, it has had numerous
|
||||||
|
cleanups and other modifications, a process simplified by the
|
||||||
|
elegance of the <a href="http://www.python.org/">Python</a>
|
||||||
|
language.</p>
|
||||||
|
|
||||||
|
<p>In 2001, the ViewCVS project was moved to <a
|
||||||
|
href="http://www.sourceforge.net">SourceForge</a>, a popular
|
||||||
|
software collaboration environment. There the project continued to
|
||||||
|
mature, releasing several stable-yet-pre-1.0 versions. In 2002,
|
||||||
|
C. Michael Pilato began implementing support for Subversion in
|
||||||
|
ViewCVS, building atop the beginnings of a version control
|
||||||
|
abstraction layer begun by Lucas Bruand. Along the way, Russell
|
||||||
|
Yanofsky delivered large improvements to that abstraction, and to
|
||||||
|
ViewCVS as whole. ViewCVS was well on its way to releasing a 1.0
|
||||||
|
version.</p>
|
||||||
|
|
||||||
|
<p>Of course, now that ViewCVS could browse Subversion repositories as
|
||||||
|
easily as CVS ones, the ViewCVS name seemed inappropriate. Also,
|
||||||
|
SourceForge's lack of support for Subversion (which was already
|
||||||
|
well past its 1.0 release, and becoming hugely popular) in its
|
||||||
|
project version control offerings was annoying ViewCVS primary
|
||||||
|
developers. So in late 2005, the decision was made to rename the
|
||||||
|
project to ViewVC, to convert the project's CVS data to Subversion,
|
||||||
|
and to move the project and its Subversion data to <a
|
||||||
|
href="http://www.tigris.org">Tigris.org</a>.</p>
|
||||||
|
|
||||||
|
<p>Today, ViewVC is being developed at <a
|
||||||
|
href="http://viewvc.tigris.org">http://viewvc.tigris.org</a> by a
|
||||||
|
small community of folks</a>.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
<h2 id="sec-viewcvs-group">The ViewCVS Group</h2>
|
||||||
|
|
||||||
|
<p>The ViewCVS Group is an informal group of people working on and
|
||||||
|
developing the ViewVC package. The current set of members are
|
||||||
|
listed below with some of their notable contributions:</p>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><a href="http://www.lyra.org/greg/">Greg Stein</a></dt>
|
||||||
|
<dd>original python port of Henner Zeller's cvsweb, secure popen
|
||||||
|
implementation, configuration file implementation, rcsparse
|
||||||
|
module, and EZT template engine</dd>
|
||||||
|
|
||||||
|
<dt>Jay Painter</dt>
|
||||||
|
<dd>CVSdb query engine</dd>
|
||||||
|
|
||||||
|
<dt>Tanaka Akira</dt>
|
||||||
|
<dd>enscript colorization and tarball generation
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>Tim Cera</dt>
|
||||||
|
<dd>CvsGraph support, log_table template, regular expression search,
|
||||||
|
and paging capability</dd>
|
||||||
|
|
||||||
|
<dt>Peter Funk</dt>
|
||||||
|
<dd>standalone server, blimp logo, and numerous improvements to
|
||||||
|
ViewVC's interfaces and documentation</dd>
|
||||||
|
|
||||||
|
<dt>Lucas Bruand</dt>
|
||||||
|
|
||||||
|
<dd>C++ RCS parser (tparse) and vclib module for supporting new
|
||||||
|
version control systems</dd>
|
||||||
|
|
||||||
|
<dt><a href="http://www.cmichaelpilato.com/">C. Michael Pilato</a></dt>
|
||||||
|
<dd>Subversion support, root_as_url alternative URL scheme,
|
||||||
|
templatization work, website design, documentation</dd>
|
||||||
|
|
||||||
|
<dt>Russell Yanofsky</dt>
|
||||||
|
<dd>Windows support and the sapi module for supporting multiple web
|
||||||
|
server interfaces, sweeping abstraction and UI improvements</dd>
|
||||||
|
|
||||||
|
<dt>James Henstridge</dt>
|
||||||
|
<dd>integrated query interface, support for querying Subversion
|
||||||
|
repositories, caching support, CSS formatting, and the EZT
|
||||||
|
"define" directive</dd>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
<h2 id="sec-site-credits">About This Site</h2>
|
||||||
|
|
||||||
|
<p>The ViewVC website was designed by <a
|
||||||
|
href="http://www.cmichaelpilato.com/">C. Michael Pilato</a>. All
|
||||||
|
HTML was hand-edited in Emacs, and the little splashes of graphical
|
||||||
|
goodness owe their existence to Adobe PhotoShop. Textual content
|
||||||
|
for the site is mostly the work of Greg Stein, but has been tweaked
|
||||||
|
through the ages by various ViewVC contributors.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
70
www/index.html
Normal file
70
www/index.html
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ViewVC - Version Control Repository Browser</title>
|
||||||
|
<!-- Custom stylations to hide the obnoxious project info -->
|
||||||
|
<style type="text/css">
|
||||||
|
#projecthome .axial { display: none; }
|
||||||
|
#apphead h1 { display: none; }
|
||||||
|
#longdescription { border: none; }
|
||||||
|
#longdescription h2 { display: none; }
|
||||||
|
#customcontent h2 { display: block; }
|
||||||
|
</style>
|
||||||
|
<!-- End custom stylations -->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="app" id="customcontent">
|
||||||
|
|
||||||
|
<h1>ViewVC — Web-based Version Control Repository Browsing</h1>
|
||||||
|
|
||||||
|
<div class="h2">
|
||||||
|
<h2>Latest Release</h2>
|
||||||
|
|
||||||
|
<p>The most recent release of ViewVC is: <strong>1.0.0-rc1</strong></p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="h2">
|
||||||
|
<h2>What Is ViewVC?</h2>
|
||||||
|
|
||||||
|
<p>ViewVC is a browser interface for CVS and Subversion version
|
||||||
|
control repositories. It generates templatized HTML to present
|
||||||
|
navigable directory, revision, and change log listings. It can
|
||||||
|
display specific versions of files as well as diffs between those
|
||||||
|
versions. Basically, ViewVC provides the bulk of the report-like
|
||||||
|
functionality you expect out of your version control tool, but much
|
||||||
|
more prettily than the average textual command-line program
|
||||||
|
output.</p>
|
||||||
|
|
||||||
|
<p>Here are some of the additional features of ViewVC:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Support for filesystem-accessible CVS and Subversion repositories</li>
|
||||||
|
<li>Individually configurable virtual host support</li>
|
||||||
|
<li>Line-based annotation/blame display</li>
|
||||||
|
<li>Revision graph capabilities (<em>CVS only</em>)</li>
|
||||||
|
<li>Syntax highlighting support</li>
|
||||||
|
<li>Commit metadata query facilities</li>
|
||||||
|
<li>Template-driven output generation</li>
|
||||||
|
<li>Colorized, side-by-side differences</li>
|
||||||
|
<li>Tarball generation (by tag/branch for CVS, by revision for
|
||||||
|
Subversion)</li>
|
||||||
|
<li>Localization support based on the Accept-Language request header</li>
|
||||||
|
<li>Ability to run either as CGI script or as a standalone
|
||||||
|
server</li>
|
||||||
|
<li>Regexp-based file searching</li>
|
||||||
|
<li>INI-like configuration file (as opposed to requiring actual code
|
||||||
|
tweaks)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>For a complete list of changes present in each release, see
|
||||||
|
ViewVC's <a
|
||||||
|
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/CHANGES?rev=HEAD"
|
||||||
|
>CHANGES</a> file.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
30
www/project_tools.html
Normal file
30
www/project_tools.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<!-- Overrides the left-nav tool bar on viewvc.tigris.org, a feature
|
||||||
|
specific to tigris.org's CEE branding. See www/overrides/ in the
|
||||||
|
look.tigris.org project for details. -->
|
||||||
|
|
||||||
|
<!-- dd --><ul>
|
||||||
|
|
||||||
|
<li><a href="http://www.viewvc.org/"
|
||||||
|
>Project website</a></li>
|
||||||
|
|
||||||
|
<!-- #################################################### --></ul></dd><dd><ul>
|
||||||
|
|
||||||
|
<li><a href="http://viewvc.tigris.org/servlets/ProjectMemberList"
|
||||||
|
>Membership</a></li>
|
||||||
|
|
||||||
|
<!-- #################################################### --></ul></dd><dd><ul>
|
||||||
|
|
||||||
|
<li><a href="http://viewvc.tigris.org/servlets/ProjectNewsList"
|
||||||
|
>Announcements</a></li>
|
||||||
|
<!-- li><a href="http://viewvc.tigris.org/servlets/ProjectForumView"
|
||||||
|
>Discussion forums</a></li -->
|
||||||
|
<li><a href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
|
||||||
|
>Mailing lists</a></li>
|
||||||
|
<li><a href="http://viewvc.tigris.org/servlets/ProjectDocumentList"
|
||||||
|
>Documents & files</a></li>
|
||||||
|
<li><a href="http://viewvc.tigris.org/source/browse/viewvc/"
|
||||||
|
>Subversion</a></li>
|
||||||
|
<li><a href="http://viewvc.tigris.org/issues/buglist.cgi?component=viewvc&issue_status=UNCONFIRMED&issue_status=NEW&issue_status=STARTED&issue_status=REOPENED"
|
||||||
|
>Issue tracker</a></li>
|
||||||
|
|
||||||
|
</ul><!-- /dd -->
|
Reference in New Issue
Block a user