Post-merge debug.
Also return some lost files back, document 4intra.net modifications in CHANGES and README files, remove 'union' authorizer and rewritehtml as the similar functionality is already provided by the core. Also fix diffs for non-bash (sh/ash/dash) shells.custis
parent
56c2b61458
commit
983f9c7379
25
CHANGES
25
CHANGES
|
@ -1,3 +1,28 @@
|
|||
4Intra.net/CUSTIS improvements
|
||||
|
||||
* Support for full-text search over file contents, including binary
|
||||
documents like *.doc and so on using Sphinx Search and Apache Tika
|
||||
server. Patched Tika with fixes for #TIKA709 and #TIKA964 is highly
|
||||
recommended:
|
||||
http://wiki.4intra.net/public/tika-app-1.2-fix-TIKA709-TIKA964.jar
|
||||
(SHA1 efef722a5e2322f7c2616d096552a48134dc5faa)
|
||||
* Access right checks in query results.
|
||||
* Access right checks for repository root directories.
|
||||
* New query parameters: repository, repo type, revision number.
|
||||
* Authorizer for CVSnt ACLs.
|
||||
* InnoDB, additional database indexes and some search query
|
||||
optimisations.
|
||||
* Support for specifying path to MySQL UNIX socket.
|
||||
* Asynchronous hook examples for updating SVN and CVS repos.
|
||||
* Slightly more correct charset guessing, especially for Russian.
|
||||
* Support for diffing added/removed files.
|
||||
* File lists in RSS feeds for 'classic' template.
|
||||
* Path configuration via a single 'viewvcinstallpath.py' file,
|
||||
not via editing multiple bin/* files.
|
||||
* Link to repository list instead of viewvc.org from the logo
|
||||
* "rcsfile service" support used to workaround command execution
|
||||
problems (forks) from Apache mod_python.
|
||||
|
||||
Version 1.2.0 (released ??-???-????)
|
||||
|
||||
* bumped minimum support Python version to 2.4
|
||||
|
|
2
INSTALL
2
INSTALL
|
@ -140,7 +140,7 @@ installation instructions.
|
|||
default_root
|
||||
root_as_url_component
|
||||
rcs_dir
|
||||
mime_types_file
|
||||
mime_types_files
|
||||
|
||||
There are some other options that are usually nice to change. See
|
||||
viewvc.conf for more information. ViewVC provides a working,
|
||||
|
|
2
README
2
README
|
@ -1,5 +1,7 @@
|
|||
ViewVC -- Viewing the content of CVS/SVN repositories with a Webbrowser.
|
||||
|
||||
This is the 4Intra.net patched version with some extra features.
|
||||
|
||||
Please read the file INSTALL for more information.
|
||||
|
||||
And see windows/README for more information on running ViewVC on
|
||||
|
|
|
@ -363,6 +363,7 @@ class Config:
|
|||
if section == root_authz_section:
|
||||
for key, value in self._get_parser_items(self.parser, section):
|
||||
params[key] = value
|
||||
params['__config'] = self
|
||||
return authorizer, params
|
||||
|
||||
def get_authorizer_params(self, authorizer=None):
|
||||
|
@ -377,6 +378,7 @@ class Config:
|
|||
sub_config = getattr(self, authz_section)
|
||||
for attr in dir(sub_config):
|
||||
params[attr] = getattr(sub_config, attr)
|
||||
params['__config'] = self
|
||||
return params
|
||||
|
||||
def guesser(self):
|
||||
|
|
24
lib/cvsdb.py
24
lib/cvsdb.py
|
@ -14,6 +14,7 @@ import sys
|
|||
import time
|
||||
import re
|
||||
import cgi
|
||||
import string
|
||||
|
||||
import vclib
|
||||
import dbi
|
||||
|
@ -530,7 +531,7 @@ class CheckinDatabase:
|
|||
' AND dirid=dirs.id AND fileid=files.id' % (commits_table, commits_table, commits_table, ','.join(ids))
|
||||
)
|
||||
|
||||
def CreateSQLQueryString(self, query):
|
||||
def CreateSQLQueryString(self, query, detect_leftover=0):
|
||||
commits_table = self.GetCommitsTable()
|
||||
fields = [
|
||||
commits_table+".*",
|
||||
|
@ -692,7 +693,7 @@ class CheckinDatabase:
|
|||
revision = rows[docid]['revision']
|
||||
fp = None
|
||||
try:
|
||||
fp, _ = self.request.get_repo(repo).repos.openfile(path, revision)
|
||||
fp, _ = self.request.get_repo(repo).repos.openfile(path, revision, {})
|
||||
content = fp.read()
|
||||
fp.close()
|
||||
content = self.guesser.utf8(content)
|
||||
|
@ -757,13 +758,14 @@ class CheckinDatabase:
|
|||
rows = self.RunSphinxQuery(query)
|
||||
else:
|
||||
# Use regular queries when document content is not searched
|
||||
rows = self.selectall(self.db, self.CreateSQLQueryString(query))
|
||||
rows = self.selectall(self.db, self.CreateSQLQueryString(query, 1))
|
||||
# Check rights
|
||||
rows = (r for r in rows if self.check_commit_access(
|
||||
r['repository_name'],
|
||||
r['dir_name'],
|
||||
r['file_name'],
|
||||
r['revision']))
|
||||
query.SetExecuted()
|
||||
|
||||
# Convert rows to commit objects
|
||||
for row in rows:
|
||||
|
@ -1211,15 +1213,13 @@ def CreateCommit():
|
|||
def CreateCheckinQuery():
|
||||
return CheckinDatabaseQuery()
|
||||
|
||||
def ConnectDatabase(cfg, readonly=0):
|
||||
if readonly:
|
||||
user = cfg.cvsdb.readonly_user
|
||||
passwd = cfg.cvsdb.readonly_passwd
|
||||
else:
|
||||
user = cfg.cvsdb.user
|
||||
passwd = cfg.cvsdb.passwd
|
||||
db = CheckinDatabase(cfg.cvsdb.host, cfg.cvsdb.port, user, passwd,
|
||||
cfg.cvsdb.database_name)
|
||||
def ConnectDatabase(cfg, request=None, readonly=0):
|
||||
db = CheckinDatabase(
|
||||
readonly = readonly,
|
||||
request = request,
|
||||
cfg = cfg.cvsdb,
|
||||
guesser = cfg.guesser(),
|
||||
)
|
||||
db.Connect()
|
||||
return db
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ server = None
|
|||
# that character as-is, and sometimes needs to embed escaped values
|
||||
# into HTML attributes.
|
||||
def escape(s):
|
||||
try: s = s.encode('utf8')
|
||||
except: pass
|
||||
s = str(s)
|
||||
s = s.replace('&', '&')
|
||||
s = s.replace('>', '>')
|
||||
|
|
|
@ -41,7 +41,7 @@ class GenericViewVCAuthorizer:
|
|||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
|
||||
class ViewVCAuthorizer(GenericViewVCAuthorizer):
|
||||
|
|
|
@ -84,7 +84,7 @@ class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
|
|||
|
||||
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
||||
if not path_parts:
|
||||
return 1
|
||||
return self.check(rootname, [], '')
|
||||
if pathtype == vclib.DIR:
|
||||
return self.check(rootname, path_parts, '')
|
||||
f = path_parts[-1]
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
# -*-python-*-
|
||||
#
|
||||
# Copyright (C) 2009 Vitaliy Filippov.
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set forth in
|
||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||
# distribution or at http://viewvc.org/license-1.html.
|
||||
#
|
||||
# For more information, visit http://viewvc.org/
|
||||
#
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
import vcauth
|
||||
import vclib
|
||||
import string
|
||||
import debug
|
||||
|
||||
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
|
||||
"""A 'union' authorizer: it makes possible to use different authorizers
|
||||
for different roots."""
|
||||
|
||||
def __init__(self, username, params={}):
|
||||
self.username = username
|
||||
self.params = params
|
||||
self.cfg = params['__config']
|
||||
self.default = params.get('default', '')
|
||||
self.byroot = {}
|
||||
self.authz = {}
|
||||
union = params.get('union', '')
|
||||
for i in union.split(','):
|
||||
if i.find(':') < 0:
|
||||
continue
|
||||
(root, auth) = i.split(':', 2)
|
||||
self.byroot[root.strip()] = auth.strip()
|
||||
|
||||
def create_authz(self, rootname):
|
||||
aname = self.byroot.get(rootname, '') or self.default
|
||||
if not aname:
|
||||
return None
|
||||
if self.authz.get(aname, None):
|
||||
return self.authz[aname]
|
||||
import imp
|
||||
fp = None
|
||||
try:
|
||||
try:
|
||||
fp, path, desc = imp.find_module(aname, vcauth.__path__)
|
||||
my_auth = imp.load_module('viewvc', fp, path, desc)
|
||||
except ImportError:
|
||||
raise
|
||||
finally:
|
||||
if fp:
|
||||
fp.close()
|
||||
params = self.cfg.get_authorizer_params(aname, rootname)
|
||||
self.authz[aname] = my_auth.ViewVCAuthorizer(self.username, params)
|
||||
return self.authz[aname]
|
||||
|
||||
def check_root_access(self, rootname):
|
||||
a = self.create_authz(rootname)
|
||||
if a:
|
||||
return a.check_root_access(rootname)
|
||||
return None
|
||||
|
||||
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
||||
a = self.create_authz(rootname)
|
||||
if a:
|
||||
return a.check_path_access(rootname, path_parts, pathtype, rev)
|
||||
return None
|
|
@ -392,7 +392,7 @@ class _diff_fp:
|
|||
args.extend(["-L", self._label(info1), "-L", self._label(info2)])
|
||||
args.extend([temp1, temp2])
|
||||
args.insert(0, diff_cmd)
|
||||
os.system("'"+"' '".join(args)+"' &> "+self.temp3)
|
||||
os.system("'"+"' '".join(args)+"' > '"+self.temp3+"' 2> '"+self.temp3+"'")
|
||||
self.fp = open(self.temp3, 'rb')
|
||||
self.fp.seek(0)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
__version__ = '1.2-dev-2243'
|
||||
__version__ = '1.2.svn2905+4intranet-1'
|
||||
|
||||
# this comes from our library; measure the startup time
|
||||
import debug
|
||||
|
@ -39,6 +39,7 @@ import types
|
|||
import urllib
|
||||
import datetime
|
||||
import locale
|
||||
import string
|
||||
|
||||
# These modules come from our library (the stub has set up the path)
|
||||
from common import _item, _RCSDIFF_NO_CHANGES, _RCSDIFF_IS_BINARY, _RCSDIFF_ERROR, TemplateData
|
||||
|
@ -152,7 +153,7 @@ class Request:
|
|||
roottype, rootpath, rootname = locate_root(self.cfg, rootname)
|
||||
if roottype:
|
||||
# Setup an Authorizer for this rootname and username
|
||||
authorizer = setup_authorizer(self.cfg, self.username, self.rootname)
|
||||
authorizer = setup_authorizer(self.cfg, self.username, rootname)
|
||||
|
||||
# Create the repository object
|
||||
if roottype == 'cvs':
|
||||
|
@ -298,7 +299,7 @@ class Request:
|
|||
debug.t_start('select-repos')
|
||||
try:
|
||||
if self.repos.roottype() == 'cvs':
|
||||
self.rootpath = vclib.ccvs.canonicalize_rootpath(rootpath)
|
||||
self.rootpath = vclib.ccvs.canonicalize_rootpath(self.rootpath)
|
||||
self.repos = vclib.ccvs.CVSRepository(self.rootname,
|
||||
self.rootpath,
|
||||
self.auth,
|
||||
|
@ -308,7 +309,7 @@ class Request:
|
|||
# $CVSHeader$
|
||||
os.environ['CVSROOT'] = self.rootpath
|
||||
elif self.repos.roottype() == 'svn':
|
||||
self.rootpath = vclib.svn.canonicalize_rootpath(rootpath)
|
||||
self.rootpath = vclib.svn.canonicalize_rootpath(self.rootpath)
|
||||
self.repos = vclib.svn.SubversionRepository(self.rootname,
|
||||
self.rootpath,
|
||||
self.auth,
|
||||
|
@ -898,6 +899,7 @@ def setup_authorizer(cfg, username, rootname=None):
|
|||
return None
|
||||
|
||||
# First, try to load a module with the configured name.
|
||||
# FIXME FIXME FIXME This hack leads to ALL authorizers having 'viewvc.ViewVCAuthorizer' as their class name
|
||||
import imp
|
||||
fp = None
|
||||
try:
|
||||
|
@ -1212,7 +1214,6 @@ _re_rewrite_url = re.compile('((http|https|ftp|file|svn|svn\+ssh)'
|
|||
# Matches email addresses
|
||||
_re_rewrite_email = re.compile('([-a-zA-Z0-9_.\+]+)@'
|
||||
'(([-a-zA-Z0-9]+\.)+[A-Za-z]{2,4})')
|
||||
_re_rewrites_html = [ [ _re_rewrite_url, r'<a href="\1">\1</a>' ] ]
|
||||
|
||||
# Matches revision references
|
||||
_re_rewrite_svnrevref = re.compile(r'\b(r|rev #?|revision #?)([0-9]+)\b')
|
||||
|
@ -1306,9 +1307,6 @@ class ViewVCHtmlFormatter:
|
|||
trunc_s = mobj.group(1)[:maxlen]
|
||||
return self._entity_encode(trunc_s), len(trunc_s)
|
||||
|
||||
def format_utf8(self, mobj, userdata, maxlen=0):
|
||||
return userdata(mobj.group(0))
|
||||
|
||||
def format_svnrevref(self, mobj, userdata, maxlen=0):
|
||||
"""Return a 2-tuple containing:
|
||||
- the text represented by MatchObject MOBJ, formatted as an
|
||||
|
@ -1455,6 +1453,10 @@ class LogFormatter:
|
|||
if self.cache.has_key((maxlen, htmlize)):
|
||||
return self.cache[(maxlen, htmlize)]
|
||||
|
||||
# UTF-8 in CVS messages.
|
||||
if self.request.roottype == 'cvs':
|
||||
self.log = self.request.utf8(self.log)
|
||||
|
||||
# If we are HTML-izing...
|
||||
if htmlize:
|
||||
# ...and we don't yet have ViewVCHtmlFormatter() object tokens...
|
||||
|
@ -1462,10 +1464,6 @@ class LogFormatter:
|
|||
# ... then get them.
|
||||
lf = ViewVCHtmlFormatter()
|
||||
|
||||
# UTF-8 in CVS messages.
|
||||
if self.request.roottype == 'cvs':
|
||||
lf.add_formatter('.*', lf.format_utf8, self.request.utf8)
|
||||
|
||||
# Rewrite URLs.
|
||||
lf.add_formatter(_re_rewrite_url, lf.format_url)
|
||||
|
||||
|
@ -1611,6 +1609,7 @@ def common_template_data(request, revision=None, mime_type=None):
|
|||
'tarball_href' : None,
|
||||
'up_href' : None,
|
||||
'username' : request.username,
|
||||
'env_user_url' : os.environ.get('user_url', ''),
|
||||
'view' : _view_codes[request.view_func],
|
||||
'view_href' : None,
|
||||
'vsn' : __version__,
|
||||
|
@ -1866,6 +1865,7 @@ def markup_stream(request, cfg, blame_data, file_lines, filename,
|
|||
c, encoding = cfg.guesser().guess_charset(content)
|
||||
if encoding:
|
||||
file_lines = c.rstrip('\n').split('\n')
|
||||
file_lines = [ i+'\n' for i in file_lines ]
|
||||
else:
|
||||
encoding = 'unknown'
|
||||
|
||||
|
@ -2042,7 +2042,7 @@ def markup_or_annotate(request, is_annotate):
|
|||
|
||||
if not mime_type or mime_type == default_mime_type:
|
||||
try:
|
||||
fp, revision = request.repos.openfile(path, rev)
|
||||
fp, revision = request.repos.openfile(path, rev, {})
|
||||
mime_type = request.cfg.guesser().guess_mime(None, None, fp)
|
||||
fp.close()
|
||||
except:
|
||||
|
@ -2292,6 +2292,7 @@ def view_roots(request):
|
|||
|
||||
# add in the roots for the selection
|
||||
roots = []
|
||||
expand_root_parents(request.cfg)
|
||||
allroots = list_roots(request)
|
||||
if len(allroots):
|
||||
rootnames = allroots.keys()
|
||||
|
@ -2795,7 +2796,7 @@ def view_log(request):
|
|||
for rev in show_revs:
|
||||
entry = _item()
|
||||
entry.rev = rev.string
|
||||
entry.state = (cvs and rev.dead and 'dead')
|
||||
entry.state = (request.roottype == 'cvs' and rev.dead and 'dead')
|
||||
entry.author = rev.author
|
||||
entry.changed = rev.changed
|
||||
entry.date = make_time_string(rev.date, cfg)
|
||||
|
@ -4392,7 +4393,8 @@ def validate_query_args(request):
|
|||
# First, make sure the the XXX_match args have valid values:
|
||||
arg_match = arg_base + '_match'
|
||||
arg_match_value = request.query_dict.get(arg_match, 'exact')
|
||||
if not arg_match_value in ('exact', 'like', 'glob', 'regex', 'notregex'):
|
||||
if not arg_match_value in ('exact', 'like', 'glob', 'regex', 'notregex') and \
|
||||
(arg_base != 'comment' or arg_match_value != 'fulltext'):
|
||||
raise debug.ViewVCException(
|
||||
'An illegal value was provided for the "%s" parameter.'
|
||||
% (arg_match),
|
||||
|
@ -4442,8 +4444,8 @@ def view_queryform(request):
|
|||
|
||||
data = common_template_data(request)
|
||||
data.merge(TemplateData({
|
||||
'repos' : request.server.escape(repos),
|
||||
'repos_match' : request.server.escape(repos_match),
|
||||
'repos' : request.server.escape(repos or ''),
|
||||
'repos_match' : request.server.escape(repos_match or ''),
|
||||
'repos_type' : escaped_query_dict_get('repos_type', ''),
|
||||
'query_revision' : escaped_query_dict_get('query_revision', ''),
|
||||
'search_content' : escaped_query_dict_get('search_content', ''),
|
||||
|
@ -4855,8 +4857,8 @@ def query_patch(request, commits):
|
|||
'400 Bad Request')
|
||||
server_fp.write('Index: %s\n===================================================================\n' % (file))
|
||||
try:
|
||||
rdate1, _, _, _ = repos.revinfo(rev1)
|
||||
rdate2, _, _, _ = repos.revinfo(rev2)
|
||||
rdate1, _, _, _, _ = repos.revinfo(rev1)
|
||||
rdate2, _, _, _, _ = repos.revinfo(rev2)
|
||||
rdate1 = datetime.date.fromtimestamp(rdate1).strftime(' %Y/%m/%d %H:%M:%S')
|
||||
rdate2 = datetime.date.fromtimestamp(rdate2).strftime(' %Y/%m/%d %H:%M:%S')
|
||||
except vclib.UnsupportedFeature:
|
||||
|
@ -4868,7 +4870,7 @@ def query_patch(request, commits):
|
|||
p2 = _path_parts(repos.get_location(file, rev2, rev2))
|
||||
else:
|
||||
p2 = _path_parts(file)
|
||||
fd, fr = repos.openfile(p2, rev2)
|
||||
fd, fr = repos.openfile(p2, rev2, {})
|
||||
if not fd or rev2 != fr:
|
||||
raise vclib.ItemNotFound(p2)
|
||||
if fd:
|
||||
|
@ -4886,7 +4888,7 @@ def query_patch(request, commits):
|
|||
p1 = _path_parts(repos.get_location(p1, rev1, rev1))
|
||||
else:
|
||||
p1 = _path_parts(file)
|
||||
fd, fr = repos.openfile(p1, rev1)
|
||||
fd, fr = repos.openfile(p1, rev1, {})
|
||||
if fd:
|
||||
fd.close()
|
||||
rev1 = fr
|
||||
|
@ -5291,15 +5293,18 @@ def find_root_in_parents(cfg, rootname, roottype):
|
|||
continue
|
||||
pp = os.path.normpath(pp[:pos].strip())
|
||||
|
||||
rootpath = None
|
||||
if roottype == 'cvs':
|
||||
rootpath = vclib.ccvs.find_root_in_parent(pp, rootname)
|
||||
roots = vclib.ccvs.expand_root_parent(pp)
|
||||
elif roottype == 'svn':
|
||||
rootpath = vclib.svn.find_root_in_parent(pp, rootname)
|
||||
|
||||
if rootpath is not None:
|
||||
return rootpath
|
||||
return None
|
||||
roots = vclib.svn.expand_root_parent(pp)
|
||||
else:
|
||||
roots = {}
|
||||
if roots.has_key(rootname):
|
||||
return roots[rootname], rootname
|
||||
for (k, v) in roots.iteritems():
|
||||
if v == rootname:
|
||||
return rootname, k
|
||||
return None, None
|
||||
|
||||
def locate_root(cfg, rootname):
|
||||
"""Return a 3-tuple ROOTTYPE, ROOTPATH, ROOTNAME for configured ROOTNAME.
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
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.
|
|
@ -0,0 +1,82 @@
|
|||
Here lie TODO items for the pluggable authz system:
|
||||
|
||||
* Subversion uses path privelege to determine visibility of revision
|
||||
metadata. That logic is pretty Subversion-specific, so it feels like it
|
||||
belongs outside the vcauth library as just a helper function in viewvc.py
|
||||
or something. The algorithm is something like this (culled from the
|
||||
CollabNet implementation, and not expected to work as edited):
|
||||
|
||||
# Subversion revision access levels
|
||||
REVISION_ACCESS_NONE = 0
|
||||
REVISION_ACCESS_PARTIAL = 1
|
||||
REVISION_ACCESS_FULL = 2
|
||||
|
||||
def check_svn_revision_access(request, rev):
|
||||
# Check our revision access cache first.
|
||||
if request.rev_access_cache.has_key(rev):
|
||||
return request.rev_access_cache[rev]
|
||||
|
||||
# Check our cached answer to the question "Does the user have
|
||||
# an all-access or a not-at-all-access pass?"
|
||||
if request.full_access is not None:
|
||||
return request.full_access \
|
||||
and REVISION_ACCESS_FULL or REVISION_ACCESS_NONE
|
||||
|
||||
# Get a list of paths changed in REV.
|
||||
### FIXME: There outta be a vclib-complaint way to do this,
|
||||
### as this won't work for vclib.svn_ra.
|
||||
import svn.fs
|
||||
rev_root = svn.fs.revision_root(self.repos.fs_ptr, rev)
|
||||
changes = svn.fs.paths_changed(rev_root)
|
||||
|
||||
# Loop over the list of changed paths, asking the access question
|
||||
# for each one. We'll track whether we've found any readable paths
|
||||
# as well as any un-readable (non-authorized) paths, and quit
|
||||
# checking as soon as we know our revision access level.
|
||||
found_readable = 0
|
||||
found_unreadable = 0
|
||||
for path in changes.keys():
|
||||
parts = _path_parts(path)
|
||||
kind = request.repos.itemtype(parts, rev)
|
||||
if kind == vclib.DIR:
|
||||
access = request.auth.check_dir_access(parts, rev)
|
||||
elif:
|
||||
access = request.auth.check_file_access(parts, rev)
|
||||
if access:
|
||||
found_readable = 1
|
||||
else:
|
||||
found_unreadable = 1
|
||||
# Optimization: if we've found at least one readable, and one
|
||||
# unreadable, we needn't ask about any more paths.
|
||||
if found_readable and found_unreadable:
|
||||
break
|
||||
|
||||
# If there are paths but we can't read any of them, no access is
|
||||
# granted.
|
||||
if len(changes) and not found_readable:
|
||||
request.rev_access_cache[rev] = REVISION_ACCESS_NONE
|
||||
# If we found at least one unreadable path, partial access is
|
||||
# granted.
|
||||
elif found_unreadable:
|
||||
request.rev_access_cache[rev] = REVISION_ACCESS_PARTIAL
|
||||
# Finally, if there were no paths at all, or none of the existing
|
||||
# ones were unreadable, grant full access.
|
||||
else:
|
||||
request.rev_access_cache[rev] = REVISION_ACCESS_FULL
|
||||
return request.rev_access_cache[rev]
|
||||
|
||||
The problems are: where does one hang the revision access cache
|
||||
so that it doesn't survive a given request? On the request, as
|
||||
shown in the edited code above?
|
||||
|
||||
Can we actually get a good interface into the vcauth layer for
|
||||
asking the all-access / no-access question? Obviously each vcauth
|
||||
provider can cache that value for itself and use it as it deems
|
||||
necessary, but ideally the revision access level question will
|
||||
want to know if said auth provider was able to answer the question
|
||||
and, if so, what the answer was.
|
||||
|
||||
Another off-the-wall idea -- let's just teach Subversion to do
|
||||
this calculation as part of a libsvn_repos API.
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,78 @@
|
|||
The following is an email from a developer who was integrating bzr
|
||||
into ViewVC in which he shares some thoughts on how to further
|
||||
abstract the version control system interactions into first-class APIs
|
||||
in the vclib module.
|
||||
|
||||
Subject: Re: [ViewCVS-dev] difflib module
|
||||
Date: Wed, 1 Jun 2005 16:59:10 -0800
|
||||
From: "Johan Rydberg" <jrydberg@gnu.org>
|
||||
To: "Michael Pilato" <cmpilato@collab.net>
|
||||
Cc: <viewcvs-dev@lyra.org>
|
||||
|
||||
"C. Michael Pilato" <cmpilato@collab.net> writes:
|
||||
|
||||
>> I've tried to minimize the changes to the viewcvs.py, but of course
|
||||
>> there are a few places where some things has to be altered.
|
||||
>
|
||||
> Well, if along the way, you have ideas about how to further abstract
|
||||
> stuff into the vclib/ modules, please post.
|
||||
|
||||
I came up with a few as off now;
|
||||
|
||||
* Generalize revision counting; svn starts from 0, bzr starts from 1.
|
||||
Can be done by a constant; request.repos.MIN_REVNO. For CVS I'm not
|
||||
sure exactly what should be done. Right now this is only used in
|
||||
view_revision_svn, so it is not a problem in the short term.
|
||||
|
||||
* Generalize view_diff;
|
||||
|
||||
* Have a repo-method diff(file1, rev1, file2, rev2, args) that returns
|
||||
(date1, date2, fp). Means human_readbale_diff and raw_diff does not
|
||||
have to parse dates. Good for VCS that does not have the date in
|
||||
the diff. [### DONE ###]
|
||||
|
||||
* I'm not sure you should require GNU diff. Some VCS may use own
|
||||
diff mechanisms (bzr uses difflib, _or_ GNU diff when needed.
|
||||
Monotone uses its own, IIRC.)
|
||||
|
||||
* Generalize view_revision ;
|
||||
|
||||
* Have a method, revision_info(), which returns (date, author, msg,
|
||||
changes) much like vclib.svn.get_revision_info. The CVS version
|
||||
can raise a ViewCVSException. [### DONE ###]
|
||||
|
||||
* Establish a convention for renamed/copied files; current should
|
||||
work good enough (change.base_path, change.base_rev) but action
|
||||
string must be same for both svn and others.
|
||||
|
||||
* request.repos.rev (or .revision) should give the current revision
|
||||
number of the repo. No need for this (from view_directory):
|
||||
|
||||
if request.roottype == 'svn':
|
||||
revision = str(vclib.svn.created_rev(request.repos, request.where))
|
||||
|
||||
If svn needs the full name of the repo, why not give it when the
|
||||
repo is created?
|
||||
|
||||
* request.repos.youngest vs vclib.svn.get_youngest_revision(REPO)
|
||||
|
||||
* More object oriented;
|
||||
|
||||
* The subversion backend is not really object oriented. viewcfg.py uses
|
||||
a lot function from vclib.svn, which could instead be methods of the
|
||||
Repository class. Example:
|
||||
|
||||
diffobj = vclib.svn.do_diff(request.repos, p1, int(rev1),
|
||||
p2, int(rev2), args)
|
||||
|
||||
This should be a method of the repository;
|
||||
|
||||
diffobj = request.repos.do_diff(p1, rev1, ...)
|
||||
|
||||
I have identified the following functions;
|
||||
|
||||
- vclib.svn.created_rev
|
||||
- vclib.svn.get_youngest_revision
|
||||
- vclib.svn.date_from_rev
|
||||
- vclib.svn.do_diff
|
||||
- vclib.svn.get_revision_info
|
|
@ -17,7 +17,7 @@
|
|||
</tr></table>
|
||||
</div>
|
||||
|
||||
<div style="float: right; padding: 5px;"><a href="http://www.viewvc.org/" title="ViewVC Home"><img src="[docroot]/images/viewvc-logo.png" alt="ViewVC logotype" width="240" height="70" /></a></div>
|
||||
<div style="float: right; padding: 5px;"><a href="[if-any roots_href][roots_href][else]http://www.viewvc.org/[end]" title="ViewVC Home"><img src="[docroot]/images/viewvc-logo.png" alt="ViewVC logotype" width="240" height="70" /></a></div>
|
||||
<h1>[page_title]</h1>
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,43 @@
|
|||
[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
|
||||
<author>[commits.author]</author>
|
||||
<pubDate>[if-any commits.rss_date][commits.rss_date][else](unknown date)[end]</pubDate>
|
||||
<description><pre>[format "xml"][format "html"][commits.log][end][end]</pre></description>
|
||||
<description>
|
||||
[format "xml"]
|
||||
<pre>[commits.log]</pre>
|
||||
<table>
|
||||
[for commits.files]
|
||||
<tr>
|
||||
<td style="vertical-align: top;">
|
||||
[define rev_href][if-any commits.files.prefer_markup][commits.files.view_href][else][if-any commits.files.download_href][commits.files.download_href][end][end][end]
|
||||
[if-any commits.files.rev][if-any rev_href]<a href="[rev_href]">[end][commits.files.rev][if-any rev_href]</a>[end][else]&nbsp;[end]
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
<a href="[commits.files.dir_href]">[commits.files.dir]/</a>
|
||||
<a href="[commits.files.log_href]">[commits.files.file]</a>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
[is commits.files.type "Add"]<ins>[end]
|
||||
[is commits.files.type "Change"]<a href="[commits.files.diff_href]">[end]
|
||||
[is commits.files.type "Remove"]<del>[end]
|
||||
[commits.files.plus]/[commits.files.minus]
|
||||
[is commits.files.type "Add"]</ins>[end]
|
||||
[is commits.files.type "Change"]</a>[end]
|
||||
[is commits.files.type "Remove"]</del>[end]
|
||||
</td>
|
||||
</tr>
|
||||
[end]
|
||||
[if-any commits.limited_files]
|
||||
<tr class="vc_row_[if-index commits even]even[else]odd[end]">
|
||||
<td>&nbsp;</td>
|
||||
<td colspan="5">
|
||||
<strong><em><small>Only first [commits.num_files] files shown.
|
||||
<a href="[limit_changes_href]">Show all files</a> or
|
||||
<a href="[queryform_href]">adjust limit</a>.</small></em></strong>
|
||||
</tr>
|
||||
[end]
|
||||
</table>
|
||||
[end]
|
||||
</description>
|
||||
</item>[end]
|
||||
</channel>
|
||||
</rss>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</div>
|
||||
|
||||
<div id="vc_logo">
|
||||
<a href="http://www.viewvc.org/"><img src="[docroot]/images/viewvc-logo.png" alt="ViewVC logotype" width="240" height="70" /></a>
|
||||
<a href="[if-any roots_href][roots_href][else]http://www.viewvc.org/[end]"><img src="[docroot]/images/viewvc-logo.png" alt="ViewVC logotype" width="240" height="70" /></a>
|
||||
</div>
|
||||
|
||||
<div id="vc_view_selection_group">
|
||||
|
|
|
@ -1,39 +1,82 @@
|
|||
[# setup page definitions]
|
||||
[define page_title]Query on:[end]
|
||||
[define page_title]Query on /[where][end]
|
||||
[define help_href][docroot]/help_rootview.html[end]
|
||||
[# end]
|
||||
|
||||
[include "include/header.ezt" "query"]
|
||||
|
||||
<p><a href="[dir_href]">
|
||||
<img src="[docroot]/images/dir.png" class="vc_icon" alt="Directory" />
|
||||
Browse Directory</a></p>
|
||||
|
||||
<form action="[query_action]" method="get">
|
||||
|
||||
<div class="vc_query_form">
|
||||
[for query_hidden_values]<input type="hidden" name="[query_hidden_values.name]" value="[query_hidden_values.value]"/>[end]
|
||||
<table cellspacing="0" cellpadding="5" class="auto">
|
||||
[if-any enable_search_content]
|
||||
<tr>
|
||||
<th style="text-align:right;vertical-align:top;">Search content:</th>
|
||||
<td><input type="text" name="search_content" value="[search_content]" size="60" /></td>
|
||||
</tr>
|
||||
[end]
|
||||
<tr>
|
||||
<th style="text-align:right;vertical-align:top;">Repository:</th>
|
||||
<td>
|
||||
<input type="text" name="repos" value="[repos]" /> <b>Repository type:</b>
|
||||
<select name="repos_type">
|
||||
<option value="">Any</option>
|
||||
<option value="cvs" [is repos_type "cvs"]selected[end]>CVS</option>
|
||||
<option value="svn" [is repos_type "svn"]selected[end]>Subversion</option>
|
||||
</select>
|
||||
<br />
|
||||
<label for="repos_match_exact">
|
||||
<input type="radio" name="repos_match" id="repos_match_exact"
|
||||
value="exact" [is repos_match "exact"]checked="checked"[end] />
|
||||
Exact match
|
||||
</label>
|
||||
<label for="repos_match_glob">
|
||||
<input type="radio" name="repos_match" id="repos_match_glob"
|
||||
value="glob" [is repos_match "glob"]checked="checked"[end] />
|
||||
Glob pattern match
|
||||
</label>
|
||||
<label for="repos_match_regex">
|
||||
<input type="radio" name="repos_match" id="repos_match_regex"
|
||||
value="regex" [is repos_match "regex"]checked="checked"[end] />
|
||||
Regex match
|
||||
</label>
|
||||
<label for="repos_match_notregex">
|
||||
<input type="radio" name="repos_match" id="repos_match_notregex"
|
||||
value="notregex" [is repos_match "notregex"]checked="checked"[end] />
|
||||
Regex doesn't match
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
[is roottype "cvs"]
|
||||
[# For subversion, the branch field is not used ]
|
||||
<tr>
|
||||
<th style="text-align:right;vertical-align:top;">Branch:</th>
|
||||
<td>
|
||||
<input type="text" name="branch" value="[branch]" />
|
||||
<input type="text" name="branch" value="[branch]" /><br />
|
||||
<label for="branch_match_exact">
|
||||
<input type="radio" name="branch_match" id="branch_match_exact"
|
||||
value="exact" [is branch_match "exact"]checked="checked"[end] />
|
||||
exact
|
||||
Exact match
|
||||
</label>
|
||||
<label for="branch_match_glob">
|
||||
<input type="radio" name="branch_match" id="branch_match_glob"
|
||||
value="glob" [is branch_match "glob"]checked="checked"[end] />
|
||||
glob pattern
|
||||
Glob pattern match
|
||||
</label>
|
||||
<label for="branch_match_regex">
|
||||
<input type="radio" name="branch_match" id="branch_match_regex"
|
||||
value="regex" [is branch_match "regex"]checked="checked"[end] />
|
||||
regex
|
||||
Regex match
|
||||
</label>
|
||||
<label for="branch_match_notregex">
|
||||
<input type="radio" name="branch_match" id="branch_match_notregex"
|
||||
value="notregex" [is branch_match "notregex"]checked="checked"[end] />
|
||||
<em>not</em> regex
|
||||
Regex doesn't match
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -41,85 +84,97 @@
|
|||
<tr>
|
||||
<th style="text-align:right;vertical-align:top;">Subdirectory:</th>
|
||||
<td>
|
||||
<input type="text" name="dir" value="[dir]" />
|
||||
<em>(You can list multiple directories separated by commas.)</em>
|
||||
<input type="text" name="dir" value="[dir]" /><br />
|
||||
(you can list multiple directories separated by commas)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="text-align:right;vertical-align:top;">File:</th>
|
||||
<td>
|
||||
<input type="text" name="file" value="[file]" />
|
||||
<input type="text" name="file" value="[file]" /><br />
|
||||
<label for="file_match_exact">
|
||||
<input type="radio" name="file_match" id="file_match_exact"
|
||||
value="exact" [is file_match "exact"]checked="checked"[end] />
|
||||
exact
|
||||
Exact match
|
||||
</label>
|
||||
<label for="file_match_glob">
|
||||
<input type="radio" name="file_match" id="file_match_glob"
|
||||
value="glob" [is file_match "glob"]checked="checked"[end] />
|
||||
glob pattern
|
||||
Glob pattern match
|
||||
</label>
|
||||
<label for="file_match_regex">
|
||||
<input type="radio" name="file_match" id="file_match_regex"
|
||||
value="regex" [is file_match "regex"]checked="checked"[end] />
|
||||
regex
|
||||
Regex match
|
||||
</label>
|
||||
<label for="file_match_notregex">
|
||||
<input type="radio" name="file_match" id="file_match_notregex"
|
||||
value="notregex" [is file_match "notregex"]checked="checked"[end] />
|
||||
<em>not</em> regex
|
||||
Regex doesn't match
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="text-align:right;vertical-align:top;">Revision number:</th>
|
||||
<td>
|
||||
<input type="text" name="query_revision" value="[query_revision]" /><br />
|
||||
(you can list multiple revision numbers separated by commas)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="text-align:right;vertical-align:top;">Who:</th>
|
||||
<td>
|
||||
<input type="text" name="who" value="[who]" />
|
||||
<input type="text" name="who" value="[who]" /><br />
|
||||
<label for="who_match_exact">
|
||||
<input type="radio" name="who_match" id="who_match_exact"
|
||||
value="exact" [is who_match "exact"]checked="checked"[end] />
|
||||
exact
|
||||
Exact match
|
||||
</label>
|
||||
<label for="who_match_glob">
|
||||
<input type="radio" name="who_match" id="who_match_glob"
|
||||
value="glob" [is who_match "glob"]checked="checked"[end] />
|
||||
glob pattern
|
||||
Glob pattern match
|
||||
</label>
|
||||
<label for="who_match_regex">
|
||||
<input type="radio" name="who_match" id="who_match_regex"
|
||||
value="regex" [is who_match "regex"]checked="checked"[end] />
|
||||
regex
|
||||
Regex match
|
||||
</label>
|
||||
<label for="who_match_notregex">
|
||||
<input type="radio" name="who_match" id="who_match_notregex"
|
||||
value="notregex" [is who_match "notregex"]checked="checked"[end] />
|
||||
<em>not</em> regex
|
||||
Regex doesn't match
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="text-align:right;vertical-align:top;">Comment:</th>
|
||||
<td>
|
||||
<input type="text" name="comment" value="[comment]" />
|
||||
<input type="text" name="comment" value="[comment]" size="40" /><br />
|
||||
<label for="comment_match_exact">
|
||||
<input type="radio" name="comment_match" id="comment_match_fulltext"
|
||||
value="fulltext" [is comment_match "fulltext"]checked=""[end] />
|
||||
Search full-text
|
||||
</label>
|
||||
<label for="comment_match_exact">
|
||||
<input type="radio" name="comment_match" id="comment_match_exact"
|
||||
value="exact" [is comment_match "exact"]checked=""[end] />
|
||||
exact
|
||||
Exact match
|
||||
</label>
|
||||
<label for="comment_match_glob">
|
||||
<input type="radio" name="comment_match" id="comment_match_glob"
|
||||
value="glob" [is comment_match "glob"]checked=""[end] />
|
||||
glob pattern
|
||||
Glob pattern match
|
||||
</label>
|
||||
<label for="comment_match_regex">
|
||||
<input type="radio" name="comment_match" id="comment_match_regex"
|
||||
value="regex" [is comment_match "regex"]checked=""[end] />
|
||||
regex
|
||||
Regex match
|
||||
</label>
|
||||
<label for="comment_match_notregex">
|
||||
<input type="radio" name="comment_match" id="comment_match_notregex"
|
||||
value="notregex" [is comment_match "notregex"]checked=""[end] />
|
||||
<em>not</em> regex
|
||||
Regex doesn't match
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -128,8 +183,10 @@
|
|||
<td>
|
||||
<select name="querysort">
|
||||
<option value="date" [is querysort "date"]selected="selected"[end]>Date</option>
|
||||
<option value="date_rev" [is querysort "date_rev"]selected="selected"[end]>Date (oldest first)</option>
|
||||
<option value="author" [is querysort "author"]selected="selected"[end]>Author</option>
|
||||
<option value="file" [is querysort "file"]selected="selected"[end]>File</option>
|
||||
<option value="relevance" [is querysort "relevance"]selected="selected"[end]>Relevance</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -186,7 +243,8 @@
|
|||
<td>
|
||||
Show at most
|
||||
<input type="text" name="limit_changes" value="[limit_changes]" size="5" />
|
||||
changed files per commit. <em>(Use 0 to show all files.)</em>
|
||||
changed files per commit.<br />
|
||||
(use 0 to show all files)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -16,8 +16,19 @@
|
|||
query capabilities, or asking your administrator to raise the
|
||||
database response size threshold.</p>
|
||||
[end]
|
||||
<p><a href="[queryform_href]">Modify query</a></p>
|
||||
<p><a href="[queryform_href]">Modify query</a>[if-any repos_root] [else]
|
||||
[if-any repos_type]
|
||||
[is repos_type "cvs"]| <a href="[querysvn_href]">Look only in SVN</a> | <a href="[queryall_href]">Look in all repos</a> [end]
|
||||
[is repos_type "svn"]| <a href="[querycvs_href]">Look only in CVS</a> | <a href="[queryall_href]">Look in all repos</a> [end]
|
||||
[else]
|
||||
| <a href="[querysvn_href]">Look only in SVN</a> | <a href="[querycvs_href]">Look only in CVS</a>
|
||||
[end]
|
||||
[end]</p>
|
||||
<p><a href="[backout_href]">Show commands which could be used to back out these changes</a></p>
|
||||
<p>
|
||||
<a href="[patch_href]">Show a patch built from these changes</a>
|
||||
[if-any patch_unsecure]<br /><b>CAUTION: selected changes are not contiguous, patch may include differences from other commits.</b>[end]
|
||||
</p>
|
||||
|
||||
<p><strong>+[plus_count]/-[minus_count]</strong> lines changed.</p>
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
MODULE = '/home/gstein/testing/cvsroot/mod_dav'
|
||||
OUTPUT = 'rlog-dump'
|
||||
|
||||
import sys
|
||||
sys.path.insert(0, '../lib')
|
||||
|
||||
import os
|
||||
import rlog
|
||||
|
||||
|
||||
def get_files(root):
|
||||
all_files = [ ]
|
||||
os.path.walk(root, _collect_files, all_files)
|
||||
all_files.sort()
|
||||
return all_files
|
||||
|
||||
def _collect_files(all_files, dir, files):
|
||||
for f in files:
|
||||
if f[-2:] == ',v':
|
||||
all_files.append(os.path.join(dir, f))
|
||||
|
||||
def get_config():
|
||||
class _blank:
|
||||
pass
|
||||
cfg = _blank()
|
||||
cfg.general = _blank()
|
||||
cfg.general.rcs_path = ''
|
||||
return cfg
|
||||
|
||||
|
||||
def gen_dump(cfg, out_fname, files, func):
|
||||
out = open(out_fname, 'w')
|
||||
for f in files:
|
||||
data = func(cfg, f)
|
||||
out.write(data.filename + '\n')
|
||||
tags = data.symbolic_name_hash.keys()
|
||||
tags.sort()
|
||||
for t in tags:
|
||||
out.write('%s:%s\n' % (t, data.symbolic_name_hash[t]))
|
||||
for e in data.rlog_entry_list:
|
||||
names = dir(e)
|
||||
names.sort()
|
||||
for n in names:
|
||||
out.write('%s=%s\n' % (n, getattr(e, n)))
|
||||
|
||||
def _test():
|
||||
cfg = get_config()
|
||||
files = get_files(MODULE)
|
||||
gen_dump(cfg, OUTPUT + '.old', files, rlog.GetRLogData)
|
||||
gen_dump(cfg, OUTPUT + '.new', files, rlog.get_data)
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/local/bin/python
|
||||
import sys, os.path
|
||||
sys.path.append( os.path.normpath(os.path.join(sys.path[0],"..","..","lib")) )
|
||||
import vclib.ccvs
|
||||
import popen
|
||||
def usage():
|
||||
print """
|
||||
co simulation using vclib!!!
|
||||
python co.py <Path to repository> <(relative) Path to file> <revision>
|
||||
"""
|
||||
sys.exit()
|
||||
def convertpath(s):
|
||||
a=(s,'')
|
||||
res=[]
|
||||
while (a[0]!=''):
|
||||
a=os.path.split(a[0])
|
||||
res= [a[1]]+res
|
||||
return res
|
||||
|
||||
def compareco(repo,file,rev):
|
||||
a=vclib.ccvs.CVSRepository("lucas",repo)
|
||||
f=a.getfile(convertpath(file)) # example: ["kdelibs","po","Attic","nl.po"]
|
||||
r=f.tree[rev]
|
||||
fp1 = r.checkout()
|
||||
fp2 = popen.popen('co',
|
||||
('-p'+rev, os.path.join(repo,file) ), 'r')
|
||||
l1 = fp1.readlines()
|
||||
l2 = fp2.readlines()
|
||||
ok=1
|
||||
for i in range(0,len(l1)-1):
|
||||
if l1[i] != l2[i+2]:
|
||||
print " Difference in line %d"% i
|
||||
print " line from CCVS %s" % l1[i]
|
||||
print " line from RCS %s" % l2[i+2]
|
||||
ok=0
|
||||
return ok
|
||||
|
||||
if len(sys.argv)==4:
|
||||
compareco(sys.argv[1],sys.argv[2],sys.argv[3])
|
||||
elif len(sys.argv)==3:
|
||||
a=vclib.ccvs.CVSRepository("lucas",sys.argv[1])
|
||||
f=a.getfile(convertpath(sys.argv[2])) # example: ["kdelibs","po","Attic","nl.po"]
|
||||
for rev in f.tree.keys():
|
||||
print ("revision: %s" % rev),
|
||||
if compareco(sys.argv[1],sys.argv[2],rev):
|
||||
print "ok"
|
||||
else:
|
||||
print "fail"
|
||||
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/local/bin/python
|
||||
import sys, os.path
|
||||
sys.path.append( os.path.normpath(os.path.join(sys.path[0],"..","..","lib")) )
|
||||
import vclib.ccvs
|
||||
import popen
|
503
viewvc-install
503
viewvc-install
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
# -*- Mode: python -*-
|
||||
#
|
||||
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
|
||||
|
@ -60,6 +60,8 @@ FILE_INFO_LIST = [
|
|||
("bin/cvsdbadmin", "bin/cvsdbadmin", 0755, 1, 0, 0),
|
||||
("bin/svndbadmin", "bin/svndbadmin", 0755, 1, 0, 0),
|
||||
("bin/make-database", "bin/make-database", 0755, 1, 0, 0),
|
||||
("bin/svnupdate-async", "bin/svnupdate-async", 0755, 1, 0, 0),
|
||||
("bin/svnupdate-async.sh", "bin/svnupdate-async.sh", 0755, 1, 0, 0),
|
||||
("conf/viewvc.conf.dist", "viewvc.conf.dist", 0644, 0, 0, 0),
|
||||
("conf/viewvc.conf.dist", "viewvc.conf", 0644, 0, 1, 0),
|
||||
("conf/cvsgraph.conf.dist", "cvsgraph.conf.dist", 0644, 0, 0, 0),
|
||||
|
@ -235,492 +237,6 @@ LEGEND
|
|||
|
||||
### If we get here, we're creating or overwriting the existing file.
|
||||
|
||||
# Read the source file's contents.
|
||||
try:
|
||||
contents = open(src_path, "rb").read()
|
||||
except IOError, e:
|
||||
error(str(e))
|
||||
|
||||
# Ensure the existence of the containing directories.
|
||||
dst_parent = os.path.dirname(destdir_path)
|
||||
if not os.path.exists(dst_parent):
|
||||
try:
|
||||
compat.makedirs(dst_parent)
|
||||
print " created %s%s" % (dst_parent, os.sep)
|
||||
except os.error, e:
|
||||
if e.errno == 17: # EEXIST: file exists
|
||||
return
|
||||
if e.errno == 13: # EACCES: permission denied
|
||||
error("You do not have permission to create directory %s" \
|
||||
% (dst_parent))
|
||||
error("Unknown error creating directory %s" \
|
||||
% (dst_parent, OSError, e))
|
||||
|
||||
# Now, write the file contents to their destination.
|
||||
try:
|
||||
exists = os.path.exists(destdir_path)
|
||||
open(destdir_path, "wb").write(contents)
|
||||
print " %s %s" \
|
||||
% (exists and 'replaced ' or 'installed', dst_path)
|
||||
except IOError, e:
|
||||
if e.errno == 13:
|
||||
# EACCES: permission denied
|
||||
error("You do not have permission to write file %s" % (dst_path))
|
||||
error("Unknown error writing file %s" % (dst_path, IOError, e))
|
||||
|
||||
# Set the files's mode.
|
||||
os.chmod(destdir_path, mode)
|
||||
|
||||
# (Optionally) compile the file.
|
||||
if compile_it:
|
||||
py_compile.compile(destdir_path, destdir_path + "c" , dst_path)
|
||||
|
||||
|
||||
def install_tree(src_path, dst_path, prompt_replace):
|
||||
"""Install a tree whose source is at SRC_PATH (which is relative
|
||||
to the ViewVC source directory) into the location DST_PATH (which
|
||||
is relative both to the global ROOT_DIR and DESTDIR settings). If
|
||||
PROMPT_REPLACE is set (and is not overridden by global setting
|
||||
CLEAN_MODE), prompt the user for how to deal with already existing
|
||||
files that differ from the to-be-installed version."""
|
||||
|
||||
orig_src_path = src_path
|
||||
orig_dst_path = dst_path
|
||||
src_path = _actual_src_path(src_path)
|
||||
dst_path = os.path.join(ROOT_DIR, string.replace(dst_path, '/', os.sep))
|
||||
destdir_path = os.path.join(DESTDIR + dst_path)
|
||||
|
||||
# Get a list of items in the directory.
|
||||
files = os.listdir(src_path)
|
||||
files.sort()
|
||||
for fname in files:
|
||||
# Ignore some stuff found in development directories, but not
|
||||
# intended for installation.
|
||||
if fname == 'CVS' or fname == '.svn' or fname == '_svn' \
|
||||
or fname[-4:] == '.pyc' or fname[-5:] == '.orig' \
|
||||
or fname[-4:] == '.rej' or fname[0] == '.' \
|
||||
or fname[-1] == '~':
|
||||
continue
|
||||
|
||||
orig_src_child = orig_src_path + '/' + fname
|
||||
orig_dst_child = orig_dst_path + '/' + fname
|
||||
|
||||
# If the item is a subdirectory, recurse. Otherwise, install the file.
|
||||
if os.path.isdir(os.path.join(src_path, fname)):
|
||||
install_tree(orig_src_child, orig_dst_child, prompt_replace)
|
||||
else:
|
||||
set_paths = 0
|
||||
compile_it = fname[-3:] == '.py'
|
||||
install_file(orig_src_child, orig_dst_child, 0644,
|
||||
set_paths, prompt_replace, compile_it)
|
||||
|
||||
# Check for .py and .pyc files that don't belong in installation.
|
||||
for fname in os.listdir(destdir_path):
|
||||
if not os.path.isfile(os.path.join(destdir_path, fname)) or \
|
||||
not ((fname[-3:] == '.py' and fname not in files) or
|
||||
(fname[-4:] == '.pyc' and fname[:-1] not in files)):
|
||||
continue
|
||||
|
||||
# If we get here, there's cruft.
|
||||
delete = None
|
||||
if CLEAN_MODE == 'true':
|
||||
delete = 1
|
||||
elif CLEAN_MODE == 'false':
|
||||
delete = 0
|
||||
else:
|
||||
print "File %s does not belong in ViewVC %s." \
|
||||
% (dst_path, version)
|
||||
while 1:
|
||||
temp = raw_input("Do you want to [D]elete it, or [L]eave "
|
||||
"it as is? ")
|
||||
temp = string.lower(temp[0])
|
||||
if temp == "l":
|
||||
delete = 0
|
||||
elif temp == "d":
|
||||
delete = 1
|
||||
|
||||
if delete is not None:
|
||||
break
|
||||
|
||||
assert delete is not None
|
||||
if delete:
|
||||
print " deleted %s" % (os.path.join(dst_path, fname))
|
||||
os.unlink(os.path.join(destdir_path, fname))
|
||||
else:
|
||||
print " preserved %s" % (os.path.join(dst_path, fname))
|
||||
|
||||
|
||||
|
||||
def usage_and_exit(errstr=None):
|
||||
stream = errstr and sys.stderr or sys.stdout
|
||||
stream.write("""Usage: %s [OPTIONS]
|
||||
|
||||
Installs the ViewVC web-based version control repository browser.
|
||||
|
||||
Options:
|
||||
|
||||
--help, -h, -? Show this usage message and exit.
|
||||
|
||||
--prefix=DIR Install ViewVC into the directory DIR. If not provided,
|
||||
the script will prompt for this information.
|
||||
|
||||
--destdir=DIR Use DIR as the DESTDIR. This is generally only used
|
||||
by package maintainers. If not provided, the script will
|
||||
prompt for this information.
|
||||
|
||||
--clean-mode= If 'true', overwrite existing ViewVC configuration files
|
||||
found in the target directory, and purge Python modules
|
||||
from the target directory that aren't part of the ViewVC
|
||||
distribution. If 'false', do not overwrite configuration
|
||||
files, and do not purge any files from the target
|
||||
directory. If not specified, the script will prompt
|
||||
for the appropriate action on a per-file basis.
|
||||
|
||||
""" % (os.path.basename(sys.argv[0])))
|
||||
if errstr:
|
||||
stream.write("ERROR: %s\n\n" % (errstr))
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Option parsing.
|
||||
try:
|
||||
optlist, args = getopt.getopt(sys.argv[1:], "h?",
|
||||
['prefix=',
|
||||
'destdir=',
|
||||
'clean-mode=',
|
||||
'help'])
|
||||
except getopt.GetoptError, e:
|
||||
usage_and_exit(str(e))
|
||||
for opt, arg in optlist:
|
||||
if opt == '--help' or opt == '-h' or opt == '-?':
|
||||
usage_and_exit()
|
||||
if opt == '--prefix':
|
||||
ROOT_DIR = arg
|
||||
if opt == '--destdir':
|
||||
DESTDIR = arg
|
||||
if opt == '--clean-mode':
|
||||
arg = arg.lower()
|
||||
if arg not in ('true', 'false'):
|
||||
usage_and_exit("Invalid value for --overwrite parameter.")
|
||||
CLEAN_MODE = arg
|
||||
|
||||
# Print the header greeting.
|
||||
print """This is the ViewVC %s installer.
|
||||
|
||||
It will allow you to choose the install path for ViewVC. You will now
|
||||
be asked some installation questions. Defaults are given in square brackets.
|
||||
Just hit [Enter] if a default is okay.
|
||||
""" % version
|
||||
|
||||
# Prompt for ROOT_DIR if none provided.
|
||||
if ROOT_DIR is None:
|
||||
if sys.platform == "win32":
|
||||
pf = os.getenv("ProgramFiles", "C:\\Program Files")
|
||||
default = os.path.join(pf, "viewvc-" + version)
|
||||
else:
|
||||
default = "/usr/local/viewvc-" + version
|
||||
temp = string.strip(raw_input("Installation path [%s]: " \
|
||||
% default))
|
||||
print
|
||||
if len(temp):
|
||||
ROOT_DIR = temp
|
||||
else:
|
||||
ROOT_DIR = default
|
||||
|
||||
# Prompt for DESTDIR if none provided.
|
||||
if DESTDIR is None:
|
||||
default = ''
|
||||
temp = string.strip(raw_input(
|
||||
"DESTDIR path (generally only used by package "
|
||||
"maintainers) [%s]: " \
|
||||
% default))
|
||||
print
|
||||
if len(temp):
|
||||
DESTDIR = temp
|
||||
else:
|
||||
DESTDIR = default
|
||||
|
||||
# Install the files.
|
||||
print "Installing ViewVC to %s%s:" \
|
||||
% (ROOT_DIR, DESTDIR and " (DESTDIR = %s)" % (DESTDIR) or "")
|
||||
for args in FILE_INFO_LIST:
|
||||
apply(install_file, args)
|
||||
for args in TREE_LIST:
|
||||
apply(install_tree, args)
|
||||
|
||||
# Write LIBRARY_DIR and CONF_PATHNAME into viewvcinstall.py config file
|
||||
viewvcinstallpath = """#!/usr/bin/python
|
||||
LIBRARY_DIR = "%s"
|
||||
CONF_PATHNAME = "%s"
|
||||
""" % (os.path.join(ROOT_DIR, 'lib'), os.path.join(ROOT_DIR, 'viewvc.conf'))
|
||||
open(os.path.join(ROOT_DIR, 'bin', 'viewvcinstallpath.py'),'wb').write(viewvcinstallpath)
|
||||
if sys.platform != 'win32':
|
||||
for i in ['cgi', 'mod_python']:
|
||||
os.symlink(os.path.join(ROOT_DIR, 'bin', 'viewvcinstallpath.py'), os.path.join(ROOT_DIR, 'bin', i, 'viewvcinstallpath.py'))
|
||||
else:
|
||||
for i in ['asp', 'cgi', 'mod_python']:
|
||||
open(os.path.join(ROOT_DIR, 'bin', i, 'viewvcinstallpath.py'),'wb').write(viewvcinstallpath)
|
||||
|
||||
# Print some final thoughts.
|
||||
print """
|
||||
|
||||
ViewVC file installation complete.
|
||||
|
||||
Consult the INSTALL document for detailed information on completing the
|
||||
installation and configuration of ViewVC on your system. Here's a brief
|
||||
overview of the remaining steps:
|
||||
|
||||
1) Edit the %s file.
|
||||
|
||||
2) Either configure an existing web server to run
|
||||
%s.
|
||||
|
||||
Or, copy %s to an
|
||||
already-configured cgi-bin directory.
|
||||
|
||||
Or, use the standalone server provided by this distribution at
|
||||
%s.
|
||||
""" % (os.path.join(ROOT_DIR, 'viewvc.conf'),
|
||||
os.path.join(ROOT_DIR, 'bin', 'cgi', 'viewvc.cgi'),
|
||||
os.path.join(ROOT_DIR, 'bin', 'cgi', 'viewvc.cgi'),
|
||||
os.path.join(ROOT_DIR, 'bin', 'standalone.py'))
|
||||
#!/usr/bin/env python
|
||||
# -*- Mode: python -*-
|
||||
#
|
||||
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set forth in
|
||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||
# distribution or at http://viewvc.org/license-1.html.
|
||||
#
|
||||
# For more information, visit http://viewvc.org/
|
||||
#
|
||||
# -----------------------------------------------------------------------
|
||||
#
|
||||
# Install script for ViewVC
|
||||
#
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import sys
|
||||
import string
|
||||
import re
|
||||
import traceback
|
||||
import py_compile
|
||||
import getopt
|
||||
import StringIO
|
||||
|
||||
# Get access to our library modules.
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), 'lib'))
|
||||
|
||||
import compat
|
||||
import viewvc
|
||||
import compat_ndiff
|
||||
version = viewvc.__version__
|
||||
|
||||
|
||||
## Installer defaults.
|
||||
DESTDIR = None
|
||||
ROOT_DIR = None
|
||||
CLEAN_MODE = None
|
||||
|
||||
|
||||
## List of files for installation.
|
||||
## tuple (source path,
|
||||
## destination path,
|
||||
## mode,
|
||||
## boolean -- search-and-replace?
|
||||
## boolean -- prompt before replacing?
|
||||
## boolean -- compile?)
|
||||
FILE_INFO_LIST = [
|
||||
("bin/cgi/viewvc.cgi", "bin/cgi/viewvc.cgi", 0755, 1, 0, 0),
|
||||
("bin/cgi/query.cgi", "bin/cgi/query.cgi", 0755, 1, 0, 0),
|
||||
("bin/mod_python/viewvc.py", "bin/mod_python/viewvc.py", 0755, 1, 0, 0),
|
||||
("bin/mod_python/query.py", "bin/mod_python/query.py", 0755, 1, 0, 0),
|
||||
("bin/mod_python/handler.py", "bin/mod_python/handler.py", 0755, 1, 0, 0),
|
||||
("bin/mod_python/.htaccess", "bin/mod_python/.htaccess", 0755, 0, 0, 0),
|
||||
("bin/standalone.py", "bin/standalone.py", 0755, 1, 0, 0),
|
||||
("bin/loginfo-handler", "bin/loginfo-handler", 0755, 1, 0, 0),
|
||||
("bin/cvsdbadmin", "bin/cvsdbadmin", 0755, 1, 0, 0),
|
||||
("bin/svndbadmin", "bin/svndbadmin", 0755, 1, 0, 0),
|
||||
("bin/make-database", "bin/make-database", 0755, 1, 0, 0),
|
||||
("bin/svnupdate-async", "bin/svnupdate-async", 0755, 1, 0, 0),
|
||||
("bin/svnupdate-async.sh", "bin/svnupdate-async.sh", 0755, 1, 0, 0),
|
||||
("conf/viewvc.conf.dist", "viewvc.conf.dist", 0644, 0, 0, 0),
|
||||
("conf/viewvc.conf.dist", "viewvc.conf", 0644, 0, 1, 0),
|
||||
("conf/cvsgraph.conf.dist", "cvsgraph.conf.dist", 0644, 0, 0, 0),
|
||||
("conf/cvsgraph.conf.dist", "cvsgraph.conf", 0644, 0, 1, 0),
|
||||
("conf/mimetypes.conf.dist", "mimetypes.conf.dist", 0644, 0, 0, 0),
|
||||
("conf/mimetypes.conf.dist", "mimetypes.conf", 0644, 0, 1, 0),
|
||||
]
|
||||
if sys.platform == "win32":
|
||||
FILE_INFO_LIST.extend([
|
||||
("bin/asp/viewvc.asp", "bin/asp/viewvc.asp", 0755, 1, 0, 0),
|
||||
("bin/asp/query.asp", "bin/asp/query.asp", 0755, 1, 0, 0),
|
||||
])
|
||||
|
||||
|
||||
## List of directories for installation.
|
||||
## type (source path,
|
||||
## destination path,
|
||||
## boolean -- prompt before replacing?)
|
||||
TREE_LIST = [
|
||||
("lib", "lib", 0),
|
||||
("templates", "templates", 1),
|
||||
("templates-contrib", "templates-contrib", 1),
|
||||
]
|
||||
|
||||
|
||||
## List of file extensions we can't show diffs for.
|
||||
BINARY_FILE_EXTS = [
|
||||
'.png',
|
||||
'.gif',
|
||||
'.jpg',
|
||||
]
|
||||
|
||||
|
||||
def _escape(str):
|
||||
"""Callback function for re.sub().
|
||||
|
||||
re.escape() is no good because it blindly puts backslashes in
|
||||
front of anything that is not a number or letter regardless of
|
||||
whether the resulting sequence will be interpreted."""
|
||||
return string.replace(str, "\\", "\\\\")
|
||||
|
||||
|
||||
def _actual_src_path(path):
|
||||
"""Return the real on-disk location of PATH, which is relative to
|
||||
the ViewVC source directory."""
|
||||
return os.path.join(os.path.dirname(sys.argv[0]),
|
||||
string.replace(path, '/', os.sep))
|
||||
|
||||
|
||||
def error(text, etype=None, evalue=None):
|
||||
"""Print error TEXT to stderr, pretty printing the optional
|
||||
exception type and value (ETYPE and EVALUE, respective), and then
|
||||
exit the program with an errorful code."""
|
||||
sys.stderr.write("\n[ERROR] %s\n" % (text))
|
||||
if etype:
|
||||
traceback.print_exception(etype, evalue, None, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def replace_var(contents, var, value):
|
||||
"""Replace instances of the variable VAR as found in file CONTENTS
|
||||
with VALUE."""
|
||||
pattern = re.compile('^' + var + r'\s*=\s*.*$', re.MULTILINE)
|
||||
repl = '%s = r"%s"' % (var, os.path.join(ROOT_DIR, value))
|
||||
return re.sub(pattern, _escape(repl), contents)
|
||||
|
||||
|
||||
def replace_paths(contents):
|
||||
"""Replace all ViewVC path placeholders found in file CONTENTS."""
|
||||
if contents[:2] == '#!':
|
||||
shbang = '#!' + sys.executable
|
||||
contents = re.sub('^#![^\n]*', _escape(shbang), contents)
|
||||
contents = replace_var(contents, 'LIBRARY_DIR', 'lib')
|
||||
contents = replace_var(contents, 'CONF_PATHNAME', 'viewvc.conf')
|
||||
return contents
|
||||
|
||||
|
||||
def install_file(src_path, dst_path, mode, subst_path_vars,
|
||||
prompt_replace, compile_it):
|
||||
"""Install a single file whose source is at SRC_PATH (which is
|
||||
relative to the ViewVC source directory) into the location
|
||||
DST_PATH (which is relative both to the global ROOT_DIR and
|
||||
DESTDIR settings), and set the file's MODE. If SUBST_PATH_VARS is
|
||||
set, substitute path variables in the file's contents. If
|
||||
PROMPT_REPLACE is set (and is not overridden by global setting
|
||||
CLEAN_MODE), prompt the user for how to deal with already existing
|
||||
files that differ from the to-be-installed version. If COMPILE_IT
|
||||
is set, compile the file as a Python module."""
|
||||
|
||||
src_path = _actual_src_path(src_path)
|
||||
dst_path = os.path.join(ROOT_DIR, string.replace(dst_path, '/', os.sep))
|
||||
destdir_path = DESTDIR + dst_path
|
||||
|
||||
overwrite = None
|
||||
if not (prompt_replace and os.path.exists(destdir_path)):
|
||||
# If the file doesn't already exist, or we've been instructed to
|
||||
# replace it without prompting, then drop in the new file and get
|
||||
# outta here.
|
||||
overwrite = 1
|
||||
else:
|
||||
# If we're here, then the file already exists, and we've possibly
|
||||
# got to prompt the user for what to do about that.
|
||||
|
||||
# Collect ndiff output from ndiff
|
||||
sys.stdout = StringIO.StringIO()
|
||||
compat_ndiff.main([destdir_path, src_path])
|
||||
ndiff_output = sys.stdout.getvalue()
|
||||
|
||||
# Return everything to normal
|
||||
sys.stdout = sys.__stdout__
|
||||
|
||||
# Collect the '+ ' and '- ' lines.
|
||||
diff_lines = []
|
||||
looking_at_diff_lines = 0
|
||||
for line in string.split(ndiff_output, '\n'):
|
||||
# Print line if it is a difference line
|
||||
if line[:2] == "+ " or line[:2] == "- " or line[:2] == "? ":
|
||||
diff_lines.append(line)
|
||||
looking_at_diff_lines = 1
|
||||
else:
|
||||
# Compress lines that are the same to print one blank line
|
||||
if looking_at_diff_lines:
|
||||
diff_lines.append("")
|
||||
looking_at_diff_lines = 0
|
||||
|
||||
# If there are no differences, we're done here.
|
||||
if not diff_lines:
|
||||
overwrite = 1
|
||||
else:
|
||||
# If we get here, there are differences.
|
||||
if CLEAN_MODE == 'true':
|
||||
overwrite = 1
|
||||
elif CLEAN_MODE == 'false':
|
||||
overwrite = 0
|
||||
else:
|
||||
print "File %s exists and is different from source file." \
|
||||
% (destdir_path)
|
||||
while 1:
|
||||
name, ext = os.path.splitext(src_path)
|
||||
if ext in BINARY_FILE_EXTS:
|
||||
temp = raw_input("Do you want to [O]verwrite or "
|
||||
"[D]o not overwrite? ")
|
||||
else:
|
||||
temp = raw_input("Do you want to [O]verwrite, [D]o "
|
||||
"not overwrite, or [V]iew "
|
||||
"differences? ")
|
||||
temp = string.lower(temp[0])
|
||||
if temp == "v" and ext not in BINARY_FILE_EXTS:
|
||||
print """
|
||||
---------------------------------------------------------------------------"""
|
||||
print string.join(diff_lines, '\n') + '\n'
|
||||
print """
|
||||
LEGEND
|
||||
A leading '- ' indicates line to remove from installed file
|
||||
A leading '+ ' indicates line to add to installed file
|
||||
A leading '? ' shows intraline differences.
|
||||
---------------------------------------------------------------------------"""
|
||||
elif temp == "d":
|
||||
overwrite = 0
|
||||
elif temp == "o":
|
||||
overwrite = 1
|
||||
|
||||
if overwrite is not None:
|
||||
break
|
||||
|
||||
assert overwrite is not None
|
||||
if not overwrite:
|
||||
print " preserved %s" % (dst_path)
|
||||
return
|
||||
|
||||
### If we get here, we're creating or overwriting the existing file.
|
||||
|
||||
# Read the source file's contents.
|
||||
try:
|
||||
contents = open(src_path, "rb").read()
|
||||
|
@ -942,6 +458,19 @@ Just hit [Enter] if a default is okay.
|
|||
for args in TREE_LIST:
|
||||
apply(install_tree, args)
|
||||
|
||||
# Write LIBRARY_DIR and CONF_PATHNAME into viewvcinstall.py config file
|
||||
viewvcinstallpath = """#!/usr/bin/python
|
||||
LIBRARY_DIR = "%s"
|
||||
CONF_PATHNAME = "%s"
|
||||
""" % (os.path.join(ROOT_DIR, 'lib'), os.path.join(ROOT_DIR, 'viewvc.conf'))
|
||||
open(os.path.join(ROOT_DIR, 'bin', 'viewvcinstallpath.py'),'wb').write(viewvcinstallpath)
|
||||
if sys.platform != 'win32':
|
||||
for i in ['cgi', 'mod_python']:
|
||||
os.symlink(os.path.join(ROOT_DIR, 'bin', 'viewvcinstallpath.py'), os.path.join(ROOT_DIR, 'bin', i, 'viewvcinstallpath.py'))
|
||||
else:
|
||||
for i in ['asp', 'cgi', 'mod_python']:
|
||||
open(os.path.join(ROOT_DIR, 'bin', i, 'viewvcinstallpath.py'),'wb').write(viewvcinstallpath)
|
||||
|
||||
# Print some final thoughts.
|
||||
print """
|
||||
|
||||
|
|
Loading…
Reference in New Issue