Improve error messages in directory view for inaccessible CVS files.

* lib/vclib/__init__.py
  (DirEntry.__init__):
    set "errors" member instead of "verboten"

* lib/vclib/bincvs/__init__.py
  (CVSRepository.listdir):
    don't skip "Attic" and "CVS" entries if we're not sure if they are
    directories

    don't skip entries in Attic/ when we can't tell if they are files or
    directories

  (CVSDirEntry.__init__):
    use "errors" argument instead of "verboten"

  (_get_logs):
    don't set "DirEntry.log_errors" member, use "errors"

  (_log_path):
    don't return file access errors here, they are returned by _check_path

  (_check_path):
    return error strings on file access errors instead of simple booleans

* lib/vclib/ccvs/__init__.py
  (CCVSRepository.dirlogs):
    don't set "DirEntry.log_errors" member, use "errors"

* lib/vclib/svn/__init__.py
* lib/vclib/svn_ra/__init__.py
  (get_logs):
    don't set "DirEntry.log_errors" member

* lib/viewcvs.py
  (view_directory):
    use "DirEntry.errors" member instead of "log_errors"

  (generate_tarball):
    use "DirEntry.errors" member instead of "verboten"

* tools/cvsdbadmin
  (RecurseUpdate):
    use "DirEntry.errors" member instead of "verboten"


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@978 8cb11bc2-c004-0410-86c3-e597b4017df7
remotes/tags/1.0.0-rc1
rey4 2004-12-03 20:44:56 +00:00
parent dd140d8f59
commit 2529196782
7 changed files with 54 additions and 45 deletions

View File

@ -68,10 +68,8 @@ class Repository:
New properties will be set on all of the DirEntry objects in the entries
list. At the very least, a "rev" property will be set to a revision
number or None if the entry doesn't have a number. And a "log_errors"
list property will be set holding a list of error messages pertaining
to the file. Other properties that may be set include "date", "author",
and "log".
number or None if the entry doesn't have a number. Other properties that
may be set include "date", "author", and "log".
The path is specified as a list of components, relative to the root
of the repository. e.g. ["subdir1", "subdir2", "filename"]
@ -101,10 +99,10 @@ class Repository:
class DirEntry:
"Instances represent items in a directory listing"
def __init__(self, name, kind, verboten=0):
def __init__(self, name, kind, errors=[]):
self.name = name
self.kind = kind
self.verboten = verboten
self.errors = errors
class Revision:
"""Instances holds information about file revisions"""

View File

@ -55,19 +55,25 @@ class CVSRepository(vclib.Repository):
full_name = self._getpath(path_parts)
for file in os.listdir(full_name):
kind, verboten = _check_path(os.path.join(full_name, file))
kind, errors = _check_path(os.path.join(full_name, file))
if kind == vclib.FILE:
if file[-2:] == ',v':
data.append(CVSDirEntry(file[:-2], kind, verboten, 0))
elif file != 'Attic' and file != 'CVS': # CVS directory is for fileattr
data.append(CVSDirEntry(file, kind, verboten, 0))
data.append(CVSDirEntry(file[:-2], kind, errors, 0))
elif kind == vclib.DIR:
if file != 'Attic' and file != 'CVS': # CVS directory is for fileattr
data.append(CVSDirEntry(file, kind, errors, 0))
else:
data.append(CVSDirEntry(file, kind, errors, 0))
full_name = os.path.join(full_name, 'Attic')
if os.path.isdir(full_name):
for file in os.listdir(full_name):
kind, verboten = _check_path(os.path.join(full_name, file))
if kind == vclib.FILE and file[-2:] == ',v':
data.append(CVSDirEntry(file[:-2], kind, verboten, 1))
kind, errors = _check_path(os.path.join(full_name, file))
if kind == vclib.FILE:
if file[-2:] == ',v':
data.append(CVSDirEntry(file[:-2], kind, errors, 1))
elif kind != vclib.DIR:
data.append(CVSDirEntry(file, kind, errors, 1))
return data
@ -234,8 +240,8 @@ class BinCVSRepository(CVSRepository):
return popen.popen(cmd, args, mode, capture_err)
class CVSDirEntry(vclib.DirEntry):
def __init__(self, name, kind, verboten, in_attic):
vclib.DirEntry.__init__(self, name, kind, verboten)
def __init__(self, name, kind, errors, in_attic):
vclib.DirEntry.__init__(self, name, kind, errors)
self.in_attic = in_attic
class Revision(vclib.Revision):
@ -784,7 +790,7 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
while len(chunk) < max_args and entries_idx < entries_len:
entry = entries[entries_idx]
path, errors = _log_path(entry, dirpath, get_dirs)
path = _log_path(entry, dirpath, get_dirs)
if path:
entry.path = path
entry.idx = entries_idx
@ -792,7 +798,6 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
# set properties even if we don't retrieve logs
entry.rev = entry.date = entry.author = entry.dead = entry.log = None
entry.log_errors = errors
entries_idx = entries_idx + 1
@ -824,7 +829,7 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
# rlog aborted
# if current file has errors, restart on the next one
if file.log_errors:
if file.errors:
chunk_idx = chunk_idx + 1
if chunk_idx < len(chunk):
entries_idx = chunk[chunk_idx].idx
@ -837,7 +842,7 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
# if rlog filename doesn't match current file and we already have an
# error message about this file, move on to the next file
while not (file and _paths_eq(file.path, filename)):
if file and file.log_errors:
if file and file.errors:
chunk_idx = chunk_idx + 1
file = chunk_idx < len(chunk) and chunk[chunk_idx] or None
continue
@ -848,7 +853,7 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
# if we get an rlog error message, restart loop without advancing
# chunk_idx cause there might be more output about the same file
if eof == _EOF_ERROR:
file.log_errors.append("rlog error: %s" % msg)
file.errors.append("rlog error: %s" % msg)
continue
if view_tag == 'MAIN' or view_tag == 'HEAD':
@ -902,11 +907,10 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
file.dead = file.kind == vclib.FILE and wanted_entry.dead
file.log = wanted_entry.log
# suppress rlog errors if we find a usable revision in the end
del file.log_errors[:]
del file.errors[:]
elif file.kind == vclib.FILE:
file.dead = 1
file.log_errors.append("No revisions exist on %s"
% (view_tag or "MAIN"))
file.errors.append("No revisions exist on %s" % (view_tag or "MAIN"))
# done with this file now, skip the rest of this file's revisions
if not eof:
@ -920,7 +924,7 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
def _log_path(entry, dirpath, getdirs):
path = name = None
errors = []
if not entry.verboten:
if not entry.errors:
if entry.kind == vclib.FILE:
path = entry.in_attic and 'Attic' or ''
name = entry.name
@ -929,12 +933,10 @@ def _log_path(entry, dirpath, getdirs):
if entry.newest_file:
path = entry.name
name = entry.newest_file
elif entry.kind == vclib.FILE:
errors.append("Repository file is not readable")
if name:
return os.path.join(dirpath, path, name + ',v'), errors
return None, errors
return os.path.join(dirpath, path, name + ',v')
return None
# ======================================================================
@ -943,11 +945,19 @@ def _log_path(entry, dirpath, getdirs):
if sys.platform == "win32":
def _check_path(path):
kind = None
errors = []
if os.path.isfile(path):
kind = vclib.FILE
elif os.path.isdir(path):
kind = vclib.DIR
return kind, not os.access(path, os.R_OK)
else:
errors.append("error: path is not a file or directory")
if not os.access(path, os.R_OK):
errors.append("error: path is not accessible")
return kind, errors
else:
_uid = os.getuid()
@ -956,8 +966,11 @@ else:
def _check_path(pathname):
try:
info = os.stat(pathname)
except os.error:
return None, 1
except os.error, e:
return None, [str(e)]
kind = None
errors = []
mode = info[stat.ST_MODE]
isdir = stat.S_ISDIR(mode)
@ -983,28 +996,28 @@ else:
else:
mask = stat.S_IROTH
valid = 1
if info[stat.ST_UID] == _uid:
if ((mode >> 6) & mask) != mask:
valid = 0
errors.append("error: path is not accessible to user %i" % _uid)
elif info[stat.ST_GID] == _gid:
if ((mode >> 3) & mask) != mask:
valid = 0
errors.append("error: path is not accessible to group %i" % _gid)
# If the process running the web server is a member of
# the group stat.ST_GID access may be granted.
# so the fall back to os.access is needed to figure this out.
elif (mode & mask) != mask:
if not os.access(pathname, isdir and (os.R_OK | os.X_OK) or os.R_OK):
valid = 0
errors.append("error: path is not accessible")
if isdir:
kind = vclib.DIR
else:
kind = vclib.FILE
return kind, not valid
else:
errors.append("error: path is not a file or directory")
return None, 1
return kind, errors
def _newest_file(dirpath):
"""Find the last modified RCS file in a directory"""

View File

@ -63,14 +63,14 @@ class CCVSRepository(CVSRepository):
for entry in entries:
entry.rev = entry.date = entry.author = entry.dead = entry.log = None
path, entry.log_errors = _log_path(entry, dirpath, subdirs)
path = _log_path(entry, dirpath, subdirs)
if path:
try:
rcsparse.Parser().parse(open(path, 'rb'), InfoSink(entry, tag, alltags))
except IOError, e:
entry.log_errors.append("rcsparse error: %s" % e)
entry.errors.append("rcsparse error: %s" % e)
except RuntimeError, e:
entry.log_errors.append("rcsparse error: %s" % e)
entry.errors.append("rcsparse error: %s" % e)
except rcsparse.RCSStopParser:
pass

View File

@ -245,7 +245,6 @@ def get_logs(svnrepos, full_name, files):
rev = _get_last_history_rev(svnrepos, path, subpool)
datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev, subpool)
date = _datestr_to_date(datestr, subpool)
file.log_errors = []
file.rev = str(rev)
file.date = date
file.author = author

View File

@ -213,7 +213,6 @@ def get_logs(svnrepos, full_name, files):
rev, author, date, log, changes = \
_get_rev_details(svnrepos, entry.created_rev, subpool)
rev_info_cache[entry.created_rev] = rev, author, date, log
file.log_errors = []
file.rev = rev
file.author = author
file.date = _datestr_to_date(date, subpool)

View File

@ -1420,7 +1420,7 @@ def view_directory(request):
row.name = file.name
row.type = (file.kind == vclib.FILE and 'file') or \
(file.kind == vclib.DIR and 'dir')
row.errors = file.log_errors
row.errors = file.errors
if (where == '') and (cfg.is_forbidden(file.name)):
continue
@ -2637,7 +2637,7 @@ def generate_tarball(out, request, tar_top, rep_top,
subdirs = [ ]
for file in entries:
if not file.verboten and file.kind == vclib.DIR:
if not file.errors and file.kind == vclib.DIR:
subdirs.append(file.name)
stack.append(tar_dir)

View File

@ -74,7 +74,7 @@ def RecurseUpdate(db, repository, directory, update):
for entry in repository.listdir(directory, {}):
path = directory + [entry.name]
if entry.verboten:
if entry.errors:
continue
if entry.kind is vclib.DIR: