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

Compare commits

...

21 Commits

Author SHA1 Message Date
cmpilato
739c51dd7c Tag the 1.1.17 final release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.1.17@2810 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 13:58:00 +00:00
cmpilato
167a2a041b Merge from trunk r2808, whose log message read like so:
Fix issue #516 ("Regression: UnboundLocalError: local variable
   'log_pagestart' referenced before assignment").
   
   * lib/viewvc.py
     (view_log): Initialize the 'log_pagestart' variable.

Also:

* CHANGES
  Note this change, and plan on a 1.1.17 release today.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2809 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 13:48:46 +00:00
cmpilato
c4483d0501 Doh! Forgot to peg the release date for 1.1.16.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2805 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 18:46:08 +00:00
cmpilato
d620bc13e7 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2803 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 17:37:47 +00:00
cmpilato
e3756ae365 Merge from trunk r2796, which fixed issue #514 (Simple file view has
page title with "Annotation of:").

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2797 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 17:01:40 +00:00
cmpilato
77ad38cbdb * CHANGES
Note another change made on the branch.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2795 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 14:40:32 +00:00
cmpilato
7feecdd512 Merge from trunk r2791 and r2792, which did the following:
Fix issue #515 ("XSS bug in diff view (CVE-2012-4533)").

   * lib/viewvc.py
     (DiffSource._get_row): Pass the "extra" line information through the
       formatter code so that, at a minimum, it's HTML-escaped.

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

   * conf/viewvc.conf.dist
     Show the default value of 'hr_funout' as 1 (which matches the
     programmatic default).

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2793 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 13:29:49 +00:00
cmpilato
a087c06a88 Merge from trunk r2788, whose log message read like so:
Fix issue #512 ("'Select for diffs' does not work across pages").
   
   * lib/viewvc.py
     (view_log): Preserve the 'log_pagestart' query value when generating
       the 'select for diff' links so that clicking the link returns you to
       the same page (modulo repagination due to new commits in the race
       window ... but let's not think about that).  Also, preserve the
       'r1' query parameter when generating the paging form.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2789 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-03 14:24:49 +00:00
cmpilato
acce6a556d Merge from trunk r2784, whose log message read like so:
Finish issue #510 ("Block the expensive display of binary files").

   Add a new configuration option 'binary_mime_types' which accepts a
   comma-delimited list of MIME content type patterns ('text/plain', or
   'image/*', etc.) against which versioned file MIME types are
   compared for the purposes of deciding whether to allow their display
   in the 'markup', 'annotate', 'diff' and 'patch' views.
   
   * conf/viewvc.conf.dist
     (binary_mime_types): Describe new option.
   
   * lib/config.py
     (_force_multi_value): Add 'binary_file_types' to the list of
       multi-value options.
     (Config.set_defaults): Initialize cfg.options.binary_mime_types.
   
   * lib/viewvc.py
     (is_binary_file_mime_type): New function.
     (get_file_view_info): Use is_binary_file_mime_type() to determine
       whether to return links to content-ful views of the input file.
     (markup_or_annotate, view_diff): Use is_binary_file_mime_type() to
       deny display of so-deemed binary files.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2785 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-09-05 14:55:05 +00:00
cmpilato
4670019d3a Merge from trunk r2781.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2782 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-22 20:23:27 +00:00
cmpilato
9ce7372e1a Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2778 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-22 18:53:40 +00:00
cmpilato
e1959ac2e5 Rolling 1.1.15 today.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2775 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-22 18:41:47 +00:00
cmpilato
cb38ccc929 Merge from trunk r2770 (more ra_svn improvements).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2773 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-19 18:50:01 +00:00
cmpilato
f2b82132c2 Merge from trunk r2771, whose log message read like so:
* lib/viewvc.py
     (LogFormatter.get): Fix a regression introduced in 1.1.14's handling
       of log messages when not HTML-ifying them (for example, when serving
       them up via RSS).
   
   Patch by: Christoph Sommer <christoph.sommer{__AT__}uibk.ac.at>

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2772 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-19 18:48:01 +00:00
cmpilato
5caf3a4437 Merge r2767 and r2768 from trunk (bugfixes to recent commits).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2769 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 01:40:03 +00:00
cmpilato
06ee4df42d Merge from trunk r2765, whose log message read like so:
Optimize revision info fetches for remote SVN repositories to avoid
   unnecessary (and somewhat expensive) work.
   
   * lib/vclib/svn/svn_ra.py
     (client_log): Add 'include_changes' parameter, pass to the
       Subversion log APIs.  Callers updated.
     (_revinfo): Was _revinfo_raw().  Add 'include_changed_paths'
       parameter.  Now handles the revinfo cache, only fetches changed
       paths when required, and bails out early of authz checks when
       possible.  All internal callers of revinfo() have been updated to
       use this interface instead.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2766 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 01:15:50 +00:00
cmpilato
0a6b13145e Merge from trunk r2763, which did somethin' a little bit like this:
Fix a couple of correctness/performance regressions in the remote SVN
   annotate view recently introduced.
   
   * lib/vclib/svn/svn_ra.py
     (RemoteSubversionRepository.annotate): Pass 'svn_cross_copies'
       option to itemlog() so that annotation history isn't unnaturally
       truncated.
     (RemoteSubversionRepository._blame_cb): Only consult the revinfo
       cache when authz checks are required.  This improves the speed of
       the operation when universal read access is granted to the user.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2764 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 00:52:29 +00:00
cmpilato
65d3568c92 Merge from trunk r2758, whose log message read like so:
Fix a security issue: When a readable path is copied from an
   unreadable one, Subversion will obscure the fact that the operation
   was a copy (by removing copyfrom info) and will deem the log message
   for the revision in which the copy occurred to be unreadable.  ViewVC
   was only doing the former bit; now it does the latter, too.
   
   * lib/vclib/svn/svn_repos.py
     (LocalSubversionRepository._get_changed_paths): Set found_unreadable
       when we have to hide a copyfrom path, too.

Also:

* CHANGES:
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2762 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 00:25:33 +00:00
cmpilato
de5b147a6f Merge the fixes for issue #353 ("Remote Subversion repositories not
fully honoring authz rules") from trunk.  This merges r2755, r2756,
r2757, r2759, and r2760, which see for detail log revision information.

Also:

* CHANGES: Note the changes this offers.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2761 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 00:03:57 +00:00
cmpilato
eb6b575701 Merge from trunk r2753, which contains some release process doc tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2754 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-12 13:06:43 +00:00
cmpilato
8d82b6f0d6 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2751 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-12 12:55:19 +00:00
8 changed files with 316 additions and 93 deletions

20
CHANGES
View File

@@ -1,3 +1,23 @@
Version 1.1.17 (released 25-Oct-2012)
* fix exception caused by uninitialized variable usage (issue #516)
Version 1.1.16 (released 24-Oct-2012)
* security fix: escape "extra" diff info to avoid XSS attack (issue #515)
* add 'binary_mime_types' configuration option and handling (issue #510)
* fix 'select for diffs' persistence across log pages (issue #512)
* remove lock status and filesize check on directories in remote SVN views
* fix bogus 'Annotation of' page title for non-annotated view (issue #514)
Version 1.1.15 (released 22-Jun-2012)
* security fix: complete authz support for remote SVN views (issue #353)
* security fix: log msg leak in SVN revision view with unreadable copy source
* fix several instances of incorrect information in remote SVN views
* increase performance of some revision metadata lookups in remote SVN views
* fix RSS feed regression introduced in 1.1.14
Version 1.1.14 (released 12-Jun-2012)
* fix annotation of svn files with non-URI-safe paths (issue #504)

View File

@@ -391,6 +391,24 @@
##
#allowed_views = annotate, diff, markup, roots
## Comma-delimited list of MIME content types (with support for fnmatch-
## style glob characters) which are considered not-human-readable and for
## which ViewVC will neither generate links to, nor support the direct
## display of, non-checkout views which carry the file's content (the
## 'markup', 'annotate', 'diff', and 'patch' views).
##
## NOTE: Handling of this option is given priority over ViewVC's
## longstanding support for showing web-friendly file formats -- even
## binary ones such as "image/jpeg" and "image/gif" -- in the 'markup'
## view. Thus, if you add "image/*" to this list, 'markup'-view
## display of JPEG, GIF, and PNG images will be disabled.
##
## Example:
## binary_mime_types = application/octet-stream, image/*, application/pdf,
## application/vnd*, application/msword, audio/*
#
#binary_mime_types =
## authorizer: The name of the ViewVC authorizer plugin to use when
## authorizing access to repository contents. This value must be the
## name of a Python module addressable as vcauth.MODULENAME (most
@@ -561,7 +579,7 @@
## (Only works well for C source files, otherwise diff's heuristic falls short.)
## ('-p' option to diff)
##
#hr_funout = 0
#hr_funout = 1
## hr_ignore_white: Ignore whitespace (indendation and stuff) for human
## readable diffs.

View File

@@ -112,6 +112,7 @@ class Config:
_force_multi_value = (
# Configuration values with multiple, comma-separated values.
'allowed_views',
'binary_mime_types',
'custom_log_formatting',
'cvs_roots',
'kv_files',
@@ -401,6 +402,7 @@ class Config:
self.options.mangle_email_addresses = 0
self.options.custom_log_formatting = []
self.options.default_file_view = "log"
self.options.binary_mime_types = []
self.options.http_expiration_time = 600
self.options.generate_etags = 1
self.options.svn_ignore_mimetype = 0

View File

@@ -54,12 +54,14 @@ def get_directory_props(ra_session, path, rev):
props = ra.svn_ra_get_dir(ra_session, path, rev)
return props
def client_log(url, start_rev, end_rev, log_limit, cross_copies,
cb_func, ctx):
def client_log(url, start_rev, end_rev, log_limit, include_changes,
cross_copies, cb_func, ctx):
include_changes = include_changes and 1 or 0
cross_copies = cross_copies and 1 or 0
try:
client.svn_client_log4([url], start_rev, start_rev, end_rev,
log_limit, 1, not cross_copies, 0, None,
cb_func, ctx)
log_limit, include_changes, not cross_copies,
0, None, cb_func, ctx)
except AttributeError:
# Wrap old svn_log_message_receiver_t interface with a
# svn_log_entry_t one.
@@ -75,15 +77,14 @@ def client_log(url, start_rev, end_rev, log_limit, cross_copies,
}
cb_func(log_entry, pool)
client.svn_client_log2([url], start_rev, end_rev, log_limit,
1, not cross_copies, cb_convert, ctx)
include_changes, not cross_copies, cb_convert, ctx)
### END COMPATABILITY CODE ###
class LogCollector:
### TODO: Make this thing authz-aware
def __init__(self, path, show_all_logs, lockinfo):
def __init__(self, path, show_all_logs, lockinfo, access_check_func):
# This class uses leading slashes for paths internally
if not path:
self.path = '/'
@@ -92,8 +93,12 @@ class LogCollector:
self.logs = []
self.show_all_logs = show_all_logs
self.lockinfo = lockinfo
self.access_check_func = access_check_func
self.done = False
def add_log(self, log_entry, pool):
if self.done:
return
paths = log_entry.changed_paths
revision = log_entry.revision
msg, author, date, revprops = _split_revprops(log_entry.revprops)
@@ -117,9 +122,13 @@ class LogCollector:
if change.copyfrom_path:
this_path = change.copyfrom_path + self.path[len(changed_path):]
if self.show_all_logs or this_path:
entry = Revision(revision, date, author, msg, None, self.lockinfo,
self.path[1:], None, None)
self.logs.append(entry)
if self.access_check_func is None \
or self.access_check_func(self.path[1:], revision):
entry = Revision(revision, date, author, msg, None, self.lockinfo,
self.path[1:], None, None)
self.logs.append(entry)
else:
self.done = True
if this_path:
self.path = this_path
@@ -255,14 +264,15 @@ class RemoteSubversionRepository(vclib.Repository):
### rev here should be the last history revision of the URL
client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev), self.ctx)
core.svn_stream_close(stream)
return SelfCleanFP(tmp_file), self._get_last_history_rev(path_parts, rev)
lh_rev, c_rev = self._get_last_history_rev(path_parts, rev)
return SelfCleanFP(tmp_file), lh_rev
def listdir(self, path_parts, rev, options):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.DIR: # does auth-check
raise vclib.Error("Path '%s' is not a directory." % path)
rev = self._getrev(rev)
entries = [ ]
entries = []
dirents, locks = self._get_dirents(path, rev)
for name in dirents.keys():
entry = dirents[name]
@@ -270,8 +280,9 @@ class RemoteSubversionRepository(vclib.Repository):
kind = vclib.DIR
elif entry.kind == core.svn_node_file:
kind = vclib.FILE
if vclib.check_path_access(self, path_parts + [name], kind, rev):
entries.append(vclib.DirEntry(name, kind))
else:
kind = None
entries.append(vclib.DirEntry(name, kind))
return entries
def dirlogs(self, path_parts, rev, entries, options):
@@ -282,11 +293,13 @@ class RemoteSubversionRepository(vclib.Repository):
dirents, locks = self._get_dirents(path, rev)
for entry in entries:
entry_path_parts = path_parts + [entry.name]
if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
dirent = dirents.get(entry.name, None)
# dirents is authz-sanitized, so ensure the entry is found therein.
if dirent is None:
continue
dirent = dirents[entry.name]
# Get authz-sanitized revision metadata.
entry.date, entry.author, entry.log, revprops, changes = \
self.revinfo(dirent.created_rev)
self._revinfo(dirent.created_rev)
entry.rev = str(dirent.created_rev)
entry.size = dirent.size
entry.lockinfo = None
@@ -300,28 +313,51 @@ class RemoteSubversionRepository(vclib.Repository):
rev = self._getrev(rev)
url = self._geturl(path)
# Use ls3 to fetch the lock status for this item.
lockinfo = None
basename = path_parts and path_parts[-1] or ""
dirents, locks = list_directory(url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
if locks.has_key(basename):
lockinfo = locks[basename].owner
# If this is a file, fetch the lock status and size (as of REV)
# for this item.
lockinfo = size_in_rev = None
if path_type == vclib.FILE:
basename = path_parts[-1]
list_url = self._geturl(self._getpath(path_parts[:-1]))
dirents, locks = list_directory(list_url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
if locks.has_key(basename):
lockinfo = locks[basename].owner
if dirents.has_key(basename):
size_in_rev = dirents[basename].size
# Special handling for the 'svn_latest_log' scenario.
### FIXME: Don't like this hack. We should just introduce
### something more direct in the vclib API.
if options.get('svn_latest_log', 0):
dir_lh_rev, dir_c_rev = self._get_last_history_rev(path_parts, rev)
date, author, log, revprops, changes = self._revinfo(dir_lh_rev)
return [vclib.Revision(dir_lh_rev, str(dir_lh_rev), date, author,
None, log, size_in_rev, lockinfo)]
def _access_checker(check_path, check_rev):
return vclib.check_path_access(self, _path_parts(check_path),
path_type, check_rev)
# It's okay if we're told to not show all logs on a file -- all
# the revisions should match correctly anyway.
lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0), lockinfo)
lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0),
lockinfo, _access_checker)
cross_copies = options.get('svn_cross_copies', 0)
log_limit = 0
if limit:
log_limit = first + limit
client_log(url, _rev2optrev(rev), _rev2optrev(1), log_limit,
client_log(url, _rev2optrev(rev), _rev2optrev(1), log_limit, 1,
cross_copies, lc.add_log, self.ctx)
revs = lc.logs
revs.sort()
prev = None
for rev in revs:
# Swap out revision info with stuff from the cache (which is
# authz-sanitized).
rev.date, rev.author, rev.log, revprops, changes \
= self._revinfo(rev.number)
rev.prev = prev
prev = rev
revs.reverse()
@@ -348,6 +384,18 @@ class RemoteSubversionRepository(vclib.Repository):
rev = self._getrev(rev)
url = self._geturl(path)
# Examine logs for the file to determine the oldest revision we are
# permitted to see.
log_options = {
'svn_cross_copies' : 1,
'svn_show_all_dir_logs' : 1,
}
revs = self.itemlog(path_parts, rev, vclib.SORTBY_REV, 0, 0, log_options)
oldest_rev = revs[-1].number
# Now calculate the annotation data. Note that we'll not
# inherently trust the provided author and date, because authz
# rules might necessitate that we strip that information out.
blame_data = []
def _blame_cb(line_no, revision, author, date,
@@ -355,22 +403,27 @@ class RemoteSubversionRepository(vclib.Repository):
prev_rev = None
if revision > 1:
prev_rev = revision - 1
# If we have an invalid revision, clear the date and author
# values. Otherwise, if we have authz filtering to do, use the
# revinfo cache to do so.
if revision < 0:
date = author = None
elif self.auth:
date, author, msg, revprops, changes = self._revinfo(revision)
# Strip text if the caller doesn't want it.
if not include_text:
line = None
blame_data.append(vclib.Annotation(line, line_no + 1, revision, prev_rev,
author, None))
author, date))
client.svn_client_blame(url, _rev2optrev(1), _rev2optrev(rev),
_blame_cb, self.ctx)
client.blame2(url, _rev2optrev(rev), _rev2optrev(oldest_rev),
_rev2optrev(rev), _blame_cb, self.ctx)
return blame_data, rev
def revinfo(self, rev):
rev = self._getrev(rev)
cached_info = self._revinfo_cache.get(rev)
if not cached_info:
cached_info = self._revinfo_raw(rev)
self._revinfo_cache[rev] = cached_info
return tuple(cached_info)
return self._revinfo(rev, 1)
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
p1 = self._getpath(path_parts1)
@@ -385,7 +438,7 @@ class RemoteSubversionRepository(vclib.Repository):
args = vclib._diff_args(type, options)
def _date_from_rev(rev):
date, author, msg, revprops, changes = self.revinfo(rev)
date, author, msg, revprops, changes = self._revinfo(rev)
return date
try:
@@ -429,45 +482,79 @@ class RemoteSubversionRepository(vclib.Repository):
def _get_dirents(self, path, rev):
"""Return a 2-type of dirents and locks, possibly reading/writing
from a local cache of that information."""
from a local cache of that information. This functions performs
authz checks, stripping out unreadable dirents."""
dir_url = self._geturl(path)
path_parts = _path_parts(path)
if path:
key = str(rev) + '/' + path
else:
key = str(rev)
# Ensure that the cache gets filled...
dirents_locks = self._dirent_cache.get(key)
if not dirents_locks:
dirents, locks = list_directory(dir_url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
tmp_dirents, locks = list_directory(dir_url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
dirents = {}
for name, dirent in tmp_dirents.items():
dirent_parts = path_parts + [name]
kind = dirent.kind
if (kind == core.svn_node_dir or kind == core.svn_node_file) \
and vclib.check_path_access(self, dirent_parts,
kind == core.svn_node_dir \
and vclib.DIR or vclib.FILE, rev):
lh_rev, c_rev = self._get_last_history_rev(dirent_parts, rev)
dirent.created_rev = lh_rev
dirents[name] = dirent
dirents_locks = [dirents, locks]
self._dirent_cache[key] = dirents_locks
# ...then return the goodies from the cache.
return dirents_locks[0], dirents_locks[1]
def _get_last_history_rev(self, path_parts, rev):
"""Return the a 2-tuple which contains:
- the last interesting revision equal to or older than REV in
the history of PATH_PARTS.
- the created_rev of of PATH_PARTS as of REV."""
path = self._getpath(path_parts)
url = self._geturl(self._getpath(path_parts))
optrev = _rev2optrev(rev)
# Get the last-changed-rev.
revisions = []
def _info_cb(path, info, pool, retval=revisions):
revisions.append(info.last_changed_rev)
client.svn_client_info(url, optrev, optrev, _info_cb, 0, self.ctx)
return revisions[0]
def _revinfo_raw(self, rev):
# return 5-tuple (date, author, msg, revprops, changes)
optrev = _rev2optrev(rev)
revs = []
last_changed_rev = revisions[0]
# Now, this object might not have been directly edited since the
# last-changed-rev, but it might have been the child of a copy.
# To determine this, we'll run a potentially no-op log between
# LAST_CHANGED_REV and REV.
lc = LogCollector(path, 1, None, None)
client_log(url, optrev, _rev2optrev(last_changed_rev), 1, 1, 0,
lc.add_log, self.ctx)
revs = lc.logs
if revs:
revs.sort()
return revs[0].number, last_changed_rev
else:
return last_changed_rev, last_changed_rev
def _revinfo_fetch(self, rev, include_changed_paths=0):
need_changes = include_changed_paths or self.auth
revs = []
def _log_cb(log_entry, pool, retval=revs):
### Subversion 1.5 and earlier didn't offer the 'changed_paths2'
### hash, and in Subversion 1.6, it's offered but broken.
try:
changed_paths = log_entry.changed_paths2
paths = (changed_paths or {}).keys()
except:
changed_paths = log_entry.changed_paths
paths = (changed_paths or {}).keys()
paths.sort(lambda a, b: _compare_paths(a, b))
# If Subversion happens to call us more than once, we choose not
# to care.
if retval:
return
revision = log_entry.revision
msg, author, date, revprops = _split_revprops(log_entry.revprops)
action_map = { 'D' : vclib.DELETED,
@@ -475,22 +562,42 @@ class RemoteSubversionRepository(vclib.Repository):
'R' : vclib.REPLACED,
'M' : vclib.MODIFIED,
}
# Easy out: if we won't use the changed-path info, just return a
# changes-less tuple.
if not need_changes:
return revs.append([date, author, msg, revprops, None])
# Subversion 1.5 and earlier didn't offer the 'changed_paths2'
# hash, and in Subversion 1.6, it's offered but broken.
try:
changed_paths = log_entry.changed_paths2
paths = (changed_paths or {}).keys()
except:
changed_paths = log_entry.changed_paths
paths = (changed_paths or {}).keys()
paths.sort(lambda a, b: _compare_paths(a, b))
# If we get this far, our caller needs changed-paths, or we need
# them for authz-related sanitization.
changes = []
found_readable = found_unreadable = 0
for path in paths:
change = changed_paths[path]
### svn_log_changed_path_t (which we might get instead of the
### svn_log_changed_path2_t we'd prefer) doesn't have the
### 'node_kind' member.
# svn_log_changed_path_t (which we might get instead of the
# svn_log_changed_path2_t we'd prefer) doesn't have the
# 'node_kind' member.
pathtype = None
if hasattr(change, 'node_kind'):
if change.node_kind == core.svn_node_dir:
pathtype = vclib.DIR
elif change.node_kind == core.svn_node_file:
pathtype = vclib.FILE
### svn_log_changed_path2_t only has the 'text_modified' and
### 'props_modified' bits in Subversion 1.7 and beyond. And
### svn_log_changed_path_t is without.
# svn_log_changed_path2_t only has the 'text_modified' and
# 'props_modified' bits in Subversion 1.7 and beyond. And
# svn_log_changed_path_t is without.
text_modified = props_modified = 0
if hasattr(change, 'text_modified'):
if change.text_modified == core.svn_tristate_true:
@@ -498,9 +605,10 @@ class RemoteSubversionRepository(vclib.Repository):
if hasattr(change, 'props_modified'):
if change.props_modified == core.svn_tristate_true:
props_modified = 1
### Wrong, diddily wrong wrong wrong. Can you say,
### "Manufacturing data left and right because it hurts to
### figure out the right stuff?"
# Wrong, diddily wrong wrong wrong. Can you say,
# "Manufacturing data left and right because it hurts to
# figure out the right stuff?"
action = action_map.get(change.action, vclib.MODIFIED)
if change.copyfrom_path and change.copyfrom_rev:
is_copy = 1
@@ -514,15 +622,16 @@ class RemoteSubversionRepository(vclib.Repository):
base_path = path
base_rev = revision - 1
### Check authz rules (we lie about the path type)
# Check authz rules (sadly, we have to lie about the path type)
parts = _path_parts(path)
if vclib.check_path_access(self, parts, vclib.FILE, revision):
if is_copy and base_path and (base_path != path):
parts = _path_parts(base_path)
if vclib.check_path_access(self, parts, vclib.FILE, base_rev):
if not vclib.check_path_access(self, parts, vclib.FILE, base_rev):
is_copy = 0
base_path = None
base_rev = None
found_unreadable = 1
changes.append(SVNChangedPath(path, revision, pathtype, base_path,
base_rev, action, is_copy,
text_modified, props_modified))
@@ -530,16 +639,45 @@ class RemoteSubversionRepository(vclib.Repository):
else:
found_unreadable = 1
# If our caller doesn't want changed-path stuff, and we have
# the info we need to make an authz determination already,
# quit this loop and get on with it.
if (not include_changed_paths) and found_unreadable and found_readable:
break
# Filter unreadable information.
if found_unreadable:
msg = None
if not found_readable:
author = None
date = None
revs.append([date, author, msg, revprops, changes])
client_log(self.rootpath, optrev, optrev, 1, 0, _log_cb, self.ctx)
# Drop unrequested changes.
if not include_changed_paths:
changes = None
# Add this revision information to the "return" array.
retval.append([date, author, msg, revprops, changes])
optrev = _rev2optrev(rev)
client_log(self.rootpath, optrev, optrev, 1, need_changes, 0,
_log_cb, self.ctx)
return tuple(revs[0])
def _revinfo(self, rev, include_changed_paths=0):
"""Internal-use, cache-friendly revision information harvester."""
# Consult the revinfo cache first. If we don't have cached info,
# or our caller wants changed paths and we don't have those for
# this revision, go do the real work.
rev = self._getrev(rev)
cached_info = self._revinfo_cache.get(rev)
if not cached_info \
or (include_changed_paths and cached_info[4] is None):
cached_info = self._revinfo_fetch(rev, include_changed_paths)
self._revinfo_cache[rev] = cached_info
return cached_info
##--- custom --##
def get_youngest_revision(self):
@@ -557,23 +695,16 @@ class RemoteSubversionRepository(vclib.Repository):
old_path = results[old_rev]
except KeyError:
raise vclib.ItemNotFound(path)
return _cleanup_path(old_path)
old_path = _cleanup_path(old_path)
old_path_parts = _path_parts(old_path)
# Check access (lying about path types)
if not vclib.check_path_access(self, old_path_parts, vclib.FILE, old_rev):
raise vclib.ItemNotFound(path)
return old_path
def created_rev(self, path, rev):
# NOTE: We can't use svn_client_propget here because the
# interfaces in that layer strip out the properties not meant for
# human consumption (such as svn:entry:committed-rev, which we are
# using here to get the created revision of PATH@REV).
kind = ra.svn_ra_check_path(self.ra_session, path, rev)
if kind == core.svn_node_none:
raise vclib.ItemNotFound(_path_parts(path))
elif kind == core.svn_node_dir:
props = get_directory_props(self.ra_session, path, rev)
elif kind == core.svn_node_file:
fetched_rev, props = ra.svn_ra_get_file(self.ra_session, path, rev, None)
return int(props.get(core.SVN_PROP_ENTRY_COMMITTED_REV,
SVN_INVALID_REVNUM))
lh_rev, c_rev = self._get_last_history_rev(_path_parts(path), rev)
return lh_rev
def last_rev(self, path, peg_revision, limit_revision=None):
"""Given PATH, known to exist in PEG_REVISION, find the youngest

View File

@@ -651,6 +651,7 @@ class LocalSubversionRepository(vclib.Repository):
is_copy = 0
change.base_path = None
change.base_rev = None
found_unreadable = 1
changedpaths[path] = SVNChangedPath(path, rev, pathtype,
change.base_path,
change.base_rev, action,

View File

@@ -14,7 +14,7 @@
#
# -----------------------------------------------------------------------
__version__ = '1.1.14-dev'
__version__ = '1.1.17'
# this comes from our library; measure the startup time
import debug
@@ -24,6 +24,7 @@ debug.t_start('imports')
# standard modules that we know are in the path or builtin
import sys
import os
import fnmatch
import gzip
import mimetypes
import re
@@ -1017,6 +1018,15 @@ def default_view(mime_type, cfg):
return view_markup
return view_checkout
def is_binary_file_mime_type(mime_type, cfg):
"""Return True iff MIME_TYPE is set and matches one of the binary
file mime type patterns in CFG."""
if mime_type:
for pattern in cfg.options.binary_mime_types:
if fnmatch.fnmatch(mime_type, pattern):
return True
return False
def get_file_view_info(request, where, rev=None, mime_type=None, pathrev=-1):
"""Return an object holding common hrefs and a viewability flag used
for various views of FILENAME at revision REV whose MIME type is
@@ -1077,7 +1087,12 @@ def get_file_view_info(request, where, rev=None, mime_type=None, pathrev=-1):
params={'revision': rev},
escape=1)
prefer_markup = default_view(mime_type, request.cfg) == view_markup
is_binary_file = is_binary_file_mime_type(mime_type, request.cfg)
if is_binary_file:
download_text_href = annotate_href = view_href = None
prefer_markup = False
else:
prefer_markup = default_view(mime_type, request.cfg) == view_markup
return _item(view_href=view_href,
download_href=download_href,
@@ -1382,6 +1397,7 @@ class LogFormatter:
# But if we're not HTML-izing...
else:
# ...then do much more simplistic transformations as necessary.
log = self.log
if cfg.options.mangle_email_addresses == 2:
log = re.sub(_re_rewrite_email, r'\1@...', log)
result_log = maxlen and log[:maxlen] or log
@@ -1830,6 +1846,11 @@ def markup_or_annotate(request, is_annotate):
revision = None
mime_type, encoding = calculate_mime_type(request, path, rev)
# Is this display blocked by 'binary_mime_types' configuration?
if is_binary_file_mime_type(mime_type, cfg):
raise debug.ViewVCException('Display of binary file content disabled '
'by configuration', '403 Forbidden')
# Is this a viewable image type?
if is_viewable_image(mime_type) \
and 'co' in cfg.options.allowed_views:
@@ -1925,7 +1946,10 @@ def markup_or_annotate(request, is_annotate):
}))
if cfg.options.show_log_in_markup:
options = {'svn_latest_log': 1} ### FIXME: No longer needed?
options = {
'svn_latest_log': 1, ### FIXME: Use of this magical value is uncool.
'svn_cross_copies': 1,
}
revs = request.repos.itemlog(path, revision, vclib.SORTBY_REV,
0, 1, options)
entry = revs[-1]
@@ -2527,6 +2551,7 @@ def view_log(request):
sortby = vclib.SORTBY_DEFAULT
first = last = 0
log_pagestart = None
if cfg.options.log_pagesize:
log_pagestart = int(request.query_dict.get('log_pagestart', 0))
total = cfg.options.log_pagesextra * cfg.options.log_pagesize
@@ -2650,7 +2675,8 @@ def view_log(request):
if selected_rev != entry.rev:
entry.sel_for_diff_href = \
request.get_url(view_func=view_log,
params={'r1': entry.rev},
params={'r1': entry.rev,
'log_pagestart': log_pagestart},
escape=1)
if entry.prev is not None:
entry.diff_to_prev_href = \
@@ -2791,7 +2817,9 @@ def view_log(request):
if cfg.options.log_pagesize:
data['log_paging_action'], data['log_paging_hidden_values'] = \
request.get_form(params={'log_pagestart': None})
request.get_form(params={'log_pagestart': None,
'r1': selected_rev,
})
data['log_pagestart'] = int(request.query_dict.get('log_pagestart',0))
data['entries'] = paging_sws(data, 'entries', data['log_pagestart'],
'rev', cfg.options.log_pagesize,
@@ -3057,7 +3085,7 @@ class DiffSource:
return _item(type='header',
line_info_left=match.group(1),
line_info_right=match.group(2),
line_info_extra=match.group(3))
line_info_extra=self._format_text(match.group(3)))
if line[0] == '\\':
# \ No newline at end of file
@@ -3272,6 +3300,13 @@ def view_patch(request):
query_dict = request.query_dict
p1, p2, rev1, rev2, sym1, sym2 = setup_diff(request)
mime_type1, encoding1 = calculate_mime_type(request, p1, rev1)
mime_type2, encoding2 = calculate_mime_type(request, p2, rev2)
if is_binary_file_mime_type(mime_type1, cfg) or \
is_binary_file_mime_type(mime_type2, cfg):
raise debug.ViewVCException('Display of binary file content disabled '
'by configuration', '403 Forbidden')
# In the absence of a format dictation in the CGI params, we'll let
# use the configured diff format, allowing 'c' to mean 'c' and
# anything else to mean 'u'.
@@ -3312,6 +3347,13 @@ def view_diff(request):
query_dict = request.query_dict
p1, p2, rev1, rev2, sym1, sym2 = setup_diff(request)
mime_type1, encoding1 = calculate_mime_type(request, p1, rev1)
mime_type2, encoding2 = calculate_mime_type(request, p2, rev2)
if is_binary_file_mime_type(mime_type1, cfg) or \
is_binary_file_mime_type(mime_type2, cfg):
raise debug.ViewVCException('Display of binary file content disabled '
'by configuration', '403 Forbidden')
# since templates are in use and subversion allows changes to the dates,
# we can't provide a strong etag
if check_freshness(request, None, '%s-%s' % (rev1, rev2), weak=1):

View File

@@ -113,8 +113,13 @@ numbers, and not literal):
http://viewvc.tigris.org/issues/editmilestones.cgi?component=viewvc&action=add
18. Send to the announce@ list a message explaining all the cool new
features, and post similar announcements to other places interested
in this sort of stuff, such as Freshmeat (http://www.freshmeat.net).
features.
19. Merge CHANGES for this release into the CHANGES file for newer
http://viewvc.tigris.org/ds/viewForumSummary.do?dsForumId=4253
19. Post a new release notification at Freecode.
https://freecode.com/projects/viewvc/releases/new
20. Merge CHANGES for this release into the CHANGES file for newer
release lines and commit.

View File

@@ -9,7 +9,11 @@
[# ------------------------------------------------------------------------- ]
[# setup page definitions]
[define page_title]Contents of /[where][end]
[is annotation "annotated"]
[define page_title]Annotation of /[where][end]
[else]
[define page_title]Contents of /[where][end]
[end]
[define help_href][docroot]/help_rootview.html[end]
[# end]