diff -Nru viewvc-1.1.5/bin/asp/query.asp viewvc-1.1.23/bin/asp/query.asp --- viewvc-1.1.5/bin/asp/query.asp 2006-03-18 02:07:36.000000000 +0000 +++ viewvc-1.1.23/bin/asp/query.asp 2014-05-02 15:01:43.000000000 +0000 @@ -3,7 +3,7 @@ # -*-python-*- # -# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 @@ -54,7 +54,10 @@ server = sapi.AspServer(Server, Request, Response, Application) try: cfg = viewvc.load_config(CONF_PATHNAME, server) - query.main(server, cfg, "viewvc.asp") + viewvc_base_url = cfg.query.viewvc_base_url + if viewvc_base_url is None: + viewvc_base_url = "viewvc.asp" + query.main(server, cfg, viewvc_base_url) finally: s.close() diff -Nru viewvc-1.1.5/bin/asp/viewvc.asp viewvc-1.1.23/bin/asp/viewvc.asp --- viewvc-1.1.5/bin/asp/viewvc.asp 2006-03-18 02:07:36.000000000 +0000 +++ viewvc-1.1.23/bin/asp/viewvc.asp 2014-05-02 15:01:43.000000000 +0000 @@ -3,7 +3,7 @@ # -*-python-*- # -# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 diff -Nru viewvc-1.1.5/bin/cgi/query.cgi viewvc-1.1.23/bin/cgi/query.cgi --- viewvc-1.1.5/bin/cgi/query.cgi 2006-03-18 02:07:36.000000000 +0000 +++ viewvc-1.1.23/bin/cgi/query.cgi 2014-05-02 15:01:43.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*-python-*- # -# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 @@ -54,4 +54,7 @@ server = sapi.CgiServer() cfg = viewvc.load_config(CONF_PATHNAME, server) -query.main(server, cfg, "viewvc.cgi") +viewvc_base_url = cfg.query.viewvc_base_url +if viewvc_base_url is None: + viewvc_base_url = "viewvc.cgi" +query.main(server, cfg, viewvc_base_url) diff -Nru viewvc-1.1.5/bin/cgi/viewvc.cgi viewvc-1.1.23/bin/cgi/viewvc.cgi --- viewvc-1.1.5/bin/cgi/viewvc.cgi 2006-03-18 02:07:36.000000000 +0000 +++ viewvc-1.1.23/bin/cgi/viewvc.cgi 2014-05-02 15:01:43.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*-python-*- # -# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 diff -Nru viewvc-1.1.5/bin/cvsdbadmin viewvc-1.1.23/bin/cvsdbadmin --- viewvc-1.1.5/bin/cvsdbadmin 2009-06-08 15:53:47.000000000 +0000 +++ viewvc-1.1.23/bin/cvsdbadmin 2014-05-02 15:01:43.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*-python-*- # -# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 diff -Nru viewvc-1.1.5/bin/loginfo-handler viewvc-1.1.23/bin/loginfo-handler --- viewvc-1.1.5/bin/loginfo-handler 2008-02-28 16:11:24.000000000 +0000 +++ viewvc-1.1.23/bin/loginfo-handler 2014-05-02 15:01:43.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*-python-*- # -# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 diff -Nru viewvc-1.1.5/bin/make-database viewvc-1.1.23/bin/make-database --- viewvc-1.1.5/bin/make-database 2009-03-18 16:45:10.000000000 +0000 +++ viewvc-1.1.23/bin/make-database 2014-05-02 15:01:43.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*-python-*- # -# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 @@ -40,7 +40,7 @@ branch varchar(64) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE branch (branch) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS checkins; CREATE TABLE checkins ( @@ -63,7 +63,7 @@ KEY dirid (dirid), KEY fileid (fileid), KEY branchid (branchid) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS descs; CREATE TABLE descs ( @@ -72,7 +72,7 @@ hash bigint(20) DEFAULT '0' NOT NULL, PRIMARY KEY (id), KEY hash (hash) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS dirs; CREATE TABLE dirs ( @@ -80,7 +80,7 @@ dir varchar(255) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE dir (dir) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS files; CREATE TABLE files ( @@ -88,7 +88,7 @@ file varchar(255) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE file (file) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS people; CREATE TABLE people ( @@ -96,7 +96,7 @@ who varchar(128) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE who (who) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS repositories; CREATE TABLE repositories ( @@ -104,7 +104,7 @@ repository varchar(64) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE repository (repository) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS tags; CREATE TABLE tags ( @@ -118,7 +118,7 @@ KEY dirid (dirid), KEY fileid (fileid), KEY branchid (branchid) -) TYPE=MyISAM; +) ENGINE=MyISAM; """ ## ------------------------------------------------------------------------ @@ -132,7 +132,7 @@ branch varchar(64) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE branch (branch) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS commits; CREATE TABLE commits ( @@ -156,7 +156,7 @@ KEY fileid (fileid), KEY branchid (branchid), KEY descid (descid) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS descs; CREATE TABLE descs ( @@ -165,7 +165,7 @@ hash bigint(20) DEFAULT '0' NOT NULL, PRIMARY KEY (id), KEY hash (hash) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS dirs; CREATE TABLE dirs ( @@ -173,7 +173,7 @@ dir varchar(255) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE dir (dir) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS files; CREATE TABLE files ( @@ -181,7 +181,7 @@ file varchar(255) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE file (file) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS people; CREATE TABLE people ( @@ -189,7 +189,7 @@ who varchar(128) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE who (who) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS repositories; CREATE TABLE repositories ( @@ -197,7 +197,7 @@ repository varchar(64) binary DEFAULT '' NOT NULL, PRIMARY KEY (id), UNIQUE repository (repository) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS tags; CREATE TABLE tags ( @@ -211,7 +211,7 @@ KEY dirid (dirid), KEY fileid (fileid), KEY branchid (branchid) -) TYPE=MyISAM; +) ENGINE=MyISAM; DROP TABLE IF EXISTS metadata; CREATE TABLE metadata ( @@ -219,7 +219,7 @@ value text, PRIMARY KEY (name), UNIQUE name (name) -) TYPE=MyISAM; +) ENGINE=MyISAM; INSERT INTO metadata (name, value) VALUES ('version', '1'); """ @@ -245,6 +245,10 @@ database for you. You will then need to set the appropriate parameters in the [cvsdb] section of your viewvc.conf file. +NOTE: If a hostname or port is supplied at the command line or during +interactive prompting, this script will pass '--protocol=TCP' to +'mysql'. + Options: --dbname=ARG Use ARG as the ViewVC database name to create. @@ -253,7 +257,8 @@ --help Show this usage message. --hostname=ARG Use ARG as the hostname for the MySQL connection. - [Default: localhost] + + --port=ARG Use ARG as the port for the MySQL connection. --password=ARG Use ARG as the password for the MySQL connection. @@ -273,10 +278,11 @@ if __name__ == "__main__": try: # Parse the command-line options, if any. - dbname = version = hostname = username = password = None + dbname = version = hostname = port = username = password = None opts, args = getopt.getopt(sys.argv[1:], '', [ 'dbname=', 'help', 'hostname=', + 'port=', 'password=', 'username=', 'version=', @@ -290,6 +296,8 @@ dbname = value elif name == '--hostname': hostname = value + elif name == '--port': + port = value elif name == '--username': username = value elif name == '--password': @@ -302,7 +310,9 @@ # Prompt for information not provided via command-line options. if hostname is None: - hostname = raw_input("MySQL Hostname [default: localhost]: ") or "" + hostname = raw_input("MySQL Hostname (leave blank for default): ") + if port is None: + port = raw_input("MySQL Port (leave blank for default): ") if username is None: username = raw_input("MySQL User: ") if password is None: @@ -310,7 +320,7 @@ if dbname is None: dbname = raw_input("ViewVC Database Name [default: ViewVC]: ") or "ViewVC" - # Create the database + # Create the database. dscript = string.replace(DATABASE_SCRIPT_COMMON, "", dbname) if version == "1.0": print BONSAI_COMPAT @@ -318,16 +328,22 @@ else: dscript = dscript + DATABASE_SCRIPT_VERSION_1 - host_option = hostname and "--host=%s" % (hostname) or "" + # Calculate command arguments. + cmd_args = "--user=%s --password=%s" % (username, password) + if hostname or port: + cmd_args = cmd_args + " --protocol=TCP" + if hostname: + cmd_args = cmd_args + " --host=%s" % (hostname) + if port: + cmd_args = cmd_args + " --port=%s" % (port) + if sys.platform == "win32": - cmd = "mysql --user=%s --password=%s %s "\ - % (username, password, host_option) + cmd = "mysql %s" % (cmd_args) mysql = os.popen(cmd, "w") # popen2.Popen3 is not provided on windows mysql.write(dscript) status = mysql.close() else: - cmd = "{ mysql --user=%s --password=%s %s ; } 2>&1" \ - % (username, password, host_option) + cmd = "{ mysql %s ; } 2>&1" % (cmd_args) pipes = popen2.Popen3(cmd) pipes.tochild.write(dscript) pipes.tochild.close() diff -Nru viewvc-1.1.5/bin/mod_python/handler.py viewvc-1.1.23/bin/mod_python/handler.py --- viewvc-1.1.5/bin/mod_python/handler.py 2006-03-18 02:07:36.000000000 +0000 +++ viewvc-1.1.23/bin/mod_python/handler.py 2014-05-02 15:01:43.000000000 +0000 @@ -1,6 +1,6 @@ # -*-python-*- # -# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 diff -Nru viewvc-1.1.5/bin/mod_python/query.py viewvc-1.1.23/bin/mod_python/query.py --- viewvc-1.1.5/bin/mod_python/query.py 2009-03-18 16:45:10.000000000 +0000 +++ viewvc-1.1.23/bin/mod_python/query.py 2014-05-02 15:01:43.000000000 +0000 @@ -1,6 +1,6 @@ # -*-python-*- # -# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 @@ -65,7 +65,10 @@ def index(req): server = sapi.ModPythonServer(req) try: - query.main(server, cfg, "viewvc.py") + viewvc_base_url = cfg.query.viewvc_base_url + if viewvc_base_url is None: + viewvc_base_url = "viewvc.py" + query.main(server, cfg, viewvc_base_url) finally: server.close() diff -Nru viewvc-1.1.5/bin/mod_python/viewvc.py viewvc-1.1.23/bin/mod_python/viewvc.py --- viewvc-1.1.5/bin/mod_python/viewvc.py 2009-03-18 16:45:10.000000000 +0000 +++ viewvc-1.1.23/bin/mod_python/viewvc.py 2014-05-02 15:01:43.000000000 +0000 @@ -1,6 +1,6 @@ # -*-python-*- # -# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 diff -Nru viewvc-1.1.5/bin/standalone.py viewvc-1.1.23/bin/standalone.py --- viewvc-1.1.5/bin/standalone.py 2009-05-05 15:49:50.000000000 +0000 +++ viewvc-1.1.23/bin/standalone.py 2014-05-02 15:01:43.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*-python-*- # -# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 1999-2014 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 @@ -17,7 +17,7 @@ __author__ = "Peter Funk " __date__ = "11 November 2001" -__version__ = "$Revision: 2143 $" +__version__ = "$Revision: 2937 $" __credits__ = """Guido van Rossum, for an excellent programming language. Greg Stein, for writing ViewCVS in the first place. Ka-Ping Yee, for the GUI code and the framework stolen from pydoc.py. @@ -41,6 +41,7 @@ import rfc822 import socket import select +import base64 import BaseHTTPServer if LIBRARY_DIR: @@ -53,291 +54,374 @@ import compat; compat.for_standalone() +# The 'crypt' module is only available on Unix platforms. We'll try +# to use 'fcrypt' if it's available (for more information, see +# http://carey.geek.nz/code/python-fcrypt/). +has_crypt = False +try: + import crypt + has_crypt = True + def _check_passwd(user_passwd, real_passwd): + return real_passwd == crypt.crypt(user_passwd, real_passwd[:2]) +except ImportError: + try: + import fcrypt + has_crypt = True + def _check_passwd(user_passwd, real_passwd): + return real_passwd == fcrypt.crypt(user_passwd, real_passwd[:2]) + except ImportError: + def _check_passwd(user_passwd, real_passwd): + return False + + class Options: - port = 49152 # default TCP/IP port used for the server - start_gui = 0 # No GUI unless requested. - daemon = 0 # stay in the foreground by default - repositories = {} # use default repositories specified in config - if sys.platform == 'mac': - host = '127.0.0.1' - else: - host = 'localhost' - script_alias = 'viewvc' - config_file = None + port = 49152 # default TCP/IP port used for the server + repositories = {} # use default repositories specified in config + host = sys.platform == 'mac' and '127.0.0.1' or 'localhost' + script_alias = 'viewvc' + config_file = None + htpasswd_file = None -# --- web browser interface: ---------------------------------------------- class StandaloneServer(sapi.CgiServer): - def __init__(self, handler): - sapi.CgiServer.__init__(self, inheritableOut = sys.platform != "win32") - self.handler = handler - - def header(self, content_type='text/html', status=None): - if not self.headerSent: - self.headerSent = 1 - if status is None: - statusCode = 200 - statusText = 'OK' - else: - p = string.find(status, ' ') - if p < 0: - statusCode = int(status) - statusText = '' - else: - statusCode = int(status[:p]) - statusText = status[p+1:] - self.handler.send_response(statusCode, statusText) - self.handler.send_header("Content-type", content_type) - for (name, value) in self.headers: - self.handler.send_header(name, value) - self.handler.end_headers() - + """Custom sapi interface that uses a BaseHTTPRequestHandler HANDLER + to generate output.""" + + def __init__(self, handler): + sapi.CgiServer.__init__(self, inheritableOut = sys.platform != "win32") + self.handler = handler + + def header(self, content_type='text/html', status=None): + if not self.headerSent: + self.headerSent = 1 + if status is None: + statusCode = 200 + statusText = 'OK' + else: + p = string.find(status, ' ') + if p < 0: + statusCode = int(status) + statusText = '' + else: + statusCode = int(status[:p]) + statusText = status[p+1:] + self.handler.send_response(statusCode, statusText) + self.handler.send_header("Content-type", content_type) + for (name, value) in self.headers: + self.handler.send_header(name, value) + self.handler.end_headers() + + +class NotViewVCLocationException(Exception): + """The request location was not aimed at ViewVC.""" + pass + + +class AuthenticationException(Exception): + """Authentication requirements have not been met.""" + pass -def serve(host, port, callback=None): - """start a HTTP server on the given port. call 'callback' when the - server is ready to serve""" - class ViewVC_Handler(BaseHTTPServer.BaseHTTPRequestHandler): - - def do_GET(self): - """Serve a GET request.""" - if not self.path or self.path == "/": - self.redirect() - elif self.is_viewvc(): - try: - self.run_viewvc() - except IOError: - # ignore IOError: [Errno 32] Broken pipe - pass - else: - self.send_error(404) - - def do_POST(self): - """Serve a POST request.""" - if self.is_viewvc(): - self.run_viewvc() - else: - self.send_error(501, "Can only POST to %s" - % (options.script_alias)) - - def is_viewvc(self): - """Check whether self.path is, or is a child of, the ScriptAlias""" - if self.path == '/' + options.script_alias: - return 1 - if self.path[:len(options.script_alias)+2] == \ - '/' + options.script_alias + '/': - return 1 - if self.path[:len(options.script_alias)+2] == \ - '/' + options.script_alias + '?': - return 1 - return 0 - - def redirect(self): - """redirect the browser to the viewvc URL""" - new_url = self.server.url + options.script_alias + '/' - self.send_response(301, "Moved (redirection follows)") - self.send_header("Content-type", "text/html") - self.send_header("Location", new_url) - self.end_headers() - self.wfile.write(""" +class ViewVCHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): + """Custom HTTP request handler for ViewVC.""" + + def do_GET(self): + """Serve a GET request.""" + self.handle_request('GET') + + def do_POST(self): + """Serve a POST request.""" + self.handle_request('POST') + + def handle_request(self, method): + """Handle a request of type METHOD.""" + try: + self.run_viewvc() + except NotViewVCLocationException: + # If the request was aimed at the server root, but there's a + # non-empty script_alias, automatically redirect to the + # script_alias. Otherwise, just return a 404 and shrug. + if (not self.path or self.path == "/") and options.script_alias: + new_url = self.server.url + options.script_alias + '/' + self.send_response(301, "Moved Permanently") + self.send_header("Content-type", "text/html") + self.send_header("Location", new_url) + self.end_headers() + self.wfile.write(""" - + +Moved Temporarily -

Redirection to ViewVC

-Wait a second. You will be automatically redirected to ViewVC. -If this doesn't work, please click on the link above. +

Redirecting to ViewVC

+

You will be automatically redirected to ViewVC. + If this doesn't work, please click on the link above.

-""" % tuple([new_url]*2)) - - def run_viewvc(self): - """This is a quick and dirty cut'n'rape from Python's - standard library module CGIHTTPServer.""" - scriptname = '/' + options.script_alias - assert string.find(self.path, scriptname) == 0 - viewvc_url = self.server.url[:-1] + scriptname - rest = self.path[len(scriptname):] - i = string.rfind(rest, '?') - if i >= 0: - rest, query = rest[:i], rest[i+1:] - else: - query = '' - # sys.stderr.write("Debug: '"+scriptname+"' '"+rest+"' '"+query+"'\n") - env = os.environ - # Since we're going to modify the env in the parent, provide empty - # values to override previously set values - for k in env.keys(): - if k[:5] == 'HTTP_': - del env[k] - for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH', - 'HTTP_USER_AGENT', 'HTTP_COOKIE'): - if env.has_key(k): - env[k] = "" - # XXX Much of the following could be prepared ahead of time! - env['SERVER_SOFTWARE'] = self.version_string() - env['SERVER_NAME'] = self.server.server_name - env['GATEWAY_INTERFACE'] = 'CGI/1.1' - env['SERVER_PROTOCOL'] = self.protocol_version - env['SERVER_PORT'] = str(self.server.server_port) - env['REQUEST_METHOD'] = self.command - uqrest = urllib.unquote(rest) - env['PATH_INFO'] = uqrest - env['SCRIPT_NAME'] = scriptname - if query: - env['QUERY_STRING'] = query - env['HTTP_HOST'] = self.server.address[0] - host = self.address_string() - if host != self.client_address[0]: - env['REMOTE_HOST'] = host - env['REMOTE_ADDR'] = self.client_address[0] - # AUTH_TYPE - # REMOTE_USER - # REMOTE_IDENT - if self.headers.typeheader is None: - env['CONTENT_TYPE'] = self.headers.type - else: - env['CONTENT_TYPE'] = self.headers.typeheader - length = self.headers.getheader('content-length') - if length: - env['CONTENT_LENGTH'] = length - accept = [] - for line in self.headers.getallmatchingheaders('accept'): - if line[:1] in string.whitespace: - accept.append(string.strip(line)) - else: - accept = accept + string.split(line[7:], ',') - env['HTTP_ACCEPT'] = string.joinfields(accept, ',') - ua = self.headers.getheader('user-agent') - if ua: - env['HTTP_USER_AGENT'] = ua - modified = self.headers.getheader('if-modified-since') - if modified: - env['HTTP_IF_MODIFIED_SINCE'] = modified - etag = self.headers.getheader('if-none-match') - if etag: - env['HTTP_IF_NONE_MATCH'] = etag - # XXX Other HTTP_* headers - decoded_query = string.replace(query, '+', ' ') - - # Preserve state, because we execute script in current process: - save_argv = sys.argv - save_stdin = sys.stdin - save_stdout = sys.stdout - save_stderr = sys.stderr - # For external tools like enscript we also need to redirect - # the real stdout file descriptor. - # - # FIXME: This code used to carry the following comment: - # - # (On windows, reassigning the sys.stdout variable is sufficient - # because pipe_cmds makes it the standard output for child - # processes.) - # - # But we no longer use pipe_cmds. So at the very least, the - # comment is stale. Is the code okay, though? - if sys.platform != "win32": save_realstdout = os.dup(1) - try: - try: - sys.stdout = self.wfile - if sys.platform != "win32": - os.dup2(self.wfile.fileno(), 1) - sys.stdin = self.rfile - viewvc.main(StandaloneServer(self), cfg) - finally: - sys.argv = save_argv - sys.stdin = save_stdin - sys.stdout.flush() - if sys.platform != "win32": - os.dup2(save_realstdout, 1) - os.close(save_realstdout) - sys.stdout = save_stdout - sys.stderr = save_stderr - except SystemExit, status: - self.log_error("ViewVC exit status %s", str(status)) - else: - self.log_error("ViewVC exited ok") - - class ViewVC_Server(BaseHTTPServer.HTTPServer): - def __init__(self, host, port, callback): - self.address = (host, port) - self.url = 'http://%s:%d/' % (host, port) - self.callback = callback - BaseHTTPServer.HTTPServer.__init__(self, self.address, - self.handler) - - def serve_until_quit(self): - self.quit = 0 - while not self.quit: - rd, wr, ex = select.select([self.socket.fileno()], [], [], 1) - if rd: - self.handle_request() - - def server_activate(self): - BaseHTTPServer.HTTPServer.server_activate(self) - if self.callback: - self.callback(self) - - def server_bind(self): - # set SO_REUSEADDR (if available on this platform) - if hasattr(socket, 'SOL_SOCKET') \ - and hasattr(socket, 'SO_REUSEADDR'): - self.socket.setsockopt(socket.SOL_SOCKET, - socket.SO_REUSEADDR, 1) - BaseHTTPServer.HTTPServer.server_bind(self) +""" % (new_url, new_url)) + else: + self.send_error(404) + except IOError: # ignore IOError: [Errno 32] Broken pipe + pass + except AuthenticationException: + self.send_response(401, "Unauthorized") + self.send_header("WWW-Authenticate", 'Basic realm="ViewVC"') + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(""" + +Authentication failed + + +

Authentication failed

+

Authentication has failed. Please retry with the correct username + and password.

+ +""") + + def is_viewvc(self): + """Check whether self.path is, or is a child of, the ScriptAlias""" + if not options.script_alias: + return 1 + if self.path == '/' + options.script_alias: + return 1 + alias_len = len(options.script_alias) + if self.path[:alias_len+2] == '/' + options.script_alias + '/': + return 1 + if self.path[:alias_len+2] == '/' + options.script_alias + '?': + return 1 + return 0 - ViewVC_Server.handler = ViewVC_Handler + def validate_password(self, htpasswd_file, username, password): + """Compare USERNAME and PASSWORD against HTPASSWD_FILE.""" + try: + lines = open(htpasswd_file, 'r').readlines() + for line in lines: + file_user, file_pass = string.split(line.rstrip(), ':', 1) + if username == file_user: + return _check_passwd(password, file_pass) + except: + pass + return False + + def run_viewvc(self): + """Run ViewVC to field a single request.""" + + ### Much of this is adapter from Python's standard library + ### module CGIHTTPServer. + + # Is this request even aimed at ViewVC? If not, complain. + if not self.is_viewvc(): + raise NotViewVCLocationException() + + # If htpasswd authentication is enabled, try to authenticate the user. + self.username = None + if options.htpasswd_file: + authn = self.headers.get('authorization') + if not authn: + raise AuthenticationException() + try: + kind, data = string.split(authn, ' ', 1) + if kind == 'Basic': + data = base64.b64decode(data) + username, password = string.split(data, ':', 1) + except: + raise AuthenticationException() + if not self.validate_password(options.htpasswd_file, username, password): + raise AuthenticationException() + self.username = username + + # Setup the environment in preparation of executing ViewVC's core code. + env = os.environ + + scriptname = options.script_alias and '/' + options.script_alias or '' + + viewvc_url = self.server.url[:-1] + scriptname + rest = self.path[len(scriptname):] + i = string.rfind(rest, '?') + if i >= 0: + rest, query = rest[:i], rest[i+1:] + else: + query = '' + # Since we're going to modify the env in the parent, provide empty + # values to override previously set values + for k in env.keys(): + if k[:5] == 'HTTP_': + del env[k] + for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH', + 'HTTP_USER_AGENT', 'HTTP_COOKIE'): + if env.has_key(k): + env[k] = "" + + # XXX Much of the following could be prepared ahead of time! + env['SERVER_SOFTWARE'] = self.version_string() + env['SERVER_NAME'] = self.server.server_name + env['GATEWAY_INTERFACE'] = 'CGI/1.1' + env['SERVER_PROTOCOL'] = self.protocol_version + env['SERVER_PORT'] = str(self.server.server_port) + env['REQUEST_METHOD'] = self.command + uqrest = urllib.unquote(rest) + env['PATH_INFO'] = uqrest + env['SCRIPT_NAME'] = scriptname + if query: + env['QUERY_STRING'] = query + env['HTTP_HOST'] = self.server.address[0] + host = self.address_string() + if host != self.client_address[0]: + env['REMOTE_HOST'] = host + env['REMOTE_ADDR'] = self.client_address[0] + if self.username: + env['REMOTE_USER'] = self.username + if self.headers.typeheader is None: + env['CONTENT_TYPE'] = self.headers.type + else: + env['CONTENT_TYPE'] = self.headers.typeheader + length = self.headers.getheader('content-length') + if length: + env['CONTENT_LENGTH'] = length + accept = [] + for line in self.headers.getallmatchingheaders('accept'): + if line[:1] in string.whitespace: + accept.append(string.strip(line)) + else: + accept = accept + string.split(line[7:], ',') + env['HTTP_ACCEPT'] = string.joinfields(accept, ',') + ua = self.headers.getheader('user-agent') + if ua: + env['HTTP_USER_AGENT'] = ua + modified = self.headers.getheader('if-modified-since') + if modified: + env['HTTP_IF_MODIFIED_SINCE'] = modified + etag = self.headers.getheader('if-none-match') + if etag: + env['HTTP_IF_NONE_MATCH'] = etag + # AUTH_TYPE + # REMOTE_IDENT + # XXX Other HTTP_* headers + + # Preserve state, because we execute script in current process: + save_argv = sys.argv + save_stdin = sys.stdin + save_stdout = sys.stdout + save_stderr = sys.stderr + # For external tools like enscript we also need to redirect + # the real stdout file descriptor. + # + # FIXME: This code used to carry the following comment: + # + # (On windows, reassigning the sys.stdout variable is sufficient + # because pipe_cmds makes it the standard output for child + # processes.) + # + # But we no longer use pipe_cmds. So at the very least, the + # comment is stale. Is the code okay, though? + if sys.platform != "win32": + save_realstdout = os.dup(1) try: - # XXX Move this code out of this function. - # Early loading of configuration here. Used to - # allow tinkering with some configuration settings: - handle_config(options.config_file) - if options.repositories: - cfg.general.default_root = "Development" - for repo_name in options.repositories.keys(): - repo_path = os.path.normpath(options.repositories[repo_name]) - if os.path.exists(os.path.join(repo_path, "CVSROOT", - "config")): - cfg.general.cvs_roots[repo_name] = repo_path - elif os.path.exists(os.path.join(repo_path, "format")): - cfg.general.svn_roots[repo_name] = repo_path - elif cfg.general.cvs_roots.has_key("Development") and \ - not os.path.isdir(cfg.general.cvs_roots["Development"]): - sys.stderr.write("*** No repository found. Please use the -r option.\n") - sys.stderr.write(" Use --help for more info.\n") - raise KeyboardInterrupt # Hack! - os.close(0) # To avoid problems with shell job control - - # always use default docroot location - cfg.options.docroot = None - - # if cvsnt isn't found, fall back to rcs - if (cfg.conf_path is None and cfg.utilities.cvsnt): - import popen - cvsnt_works = 0 - try: - fp = popen.popen(cfg.utilities.cvsnt, ['--version'], 'rt') - try: - while 1: - line = fp.readline() - if not line: break - if string.find(line, "Concurrent Versions System (CVSNT)")>=0: - cvsnt_works = 1 - while fp.read(4096): - pass - break - finally: - fp.close() - except: - pass - if not cvsnt_works: - cfg.utilities.cvsnt = None + try: + sys.stdout = self.wfile + if sys.platform != "win32": + os.dup2(self.wfile.fileno(), 1) + sys.stdin = self.rfile + viewvc.main(StandaloneServer(self), cfg) + finally: + sys.argv = save_argv + sys.stdin = save_stdin + sys.stdout.flush() + if sys.platform != "win32": + os.dup2(save_realstdout, 1) + os.close(save_realstdout) + sys.stdout = save_stdout + sys.stderr = save_stderr + except SystemExit, status: + self.log_error("ViewVC exit status %s", str(status)) + else: + self.log_error("ViewVC exited ok") - ViewVC_Server(host, port, callback).serve_until_quit() - except (KeyboardInterrupt, select.error): +class ViewVCHTTPServer(BaseHTTPServer.HTTPServer): + """Customized HTTP server for ViewVC.""" + + def __init__(self, host, port, callback): + self.address = (host, port) + self.url = 'http://%s:%d/' % (host, port) + self.callback = callback + BaseHTTPServer.HTTPServer.__init__(self, self.address, self.handler) + + def serve_until_quit(self): + self.quit = 0 + while not self.quit: + rd, wr, ex = select.select([self.socket.fileno()], [], [], 1) + if rd: + self.handle_request() + + def server_activate(self): + BaseHTTPServer.HTTPServer.server_activate(self) + if self.callback: + self.callback(self) + + def server_bind(self): + # set SO_REUSEADDR (if available on this platform) + if hasattr(socket, 'SOL_SOCKET') and hasattr(socket, 'SO_REUSEADDR'): + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + BaseHTTPServer.HTTPServer.server_bind(self) + +def serve(host, port, callback=None): + """Start an HTTP server for HOST on PORT. Call CALLBACK function + when the server is ready to serve.""" + + ViewVCHTTPServer.handler = ViewVCHTTPRequestHandler + + try: + # XXX Move this code out of this function. + # Early loading of configuration here. Used to allow tinkering + # with some configuration settings: + handle_config(options.config_file) + if options.repositories: + cfg.general.default_root = "Development" + for repo_name in options.repositories.keys(): + repo_path = os.path.normpath(options.repositories[repo_name]) + if os.path.exists(os.path.join(repo_path, "CVSROOT", "config")): + cfg.general.cvs_roots[repo_name] = repo_path + elif os.path.exists(os.path.join(repo_path, "format")): + cfg.general.svn_roots[repo_name] = repo_path + elif cfg.general.cvs_roots.has_key("Development") and \ + not os.path.isdir(cfg.general.cvs_roots["Development"]): + sys.stderr.write("*** No repository found. Please use the -r option.\n") + sys.stderr.write(" Use --help for more info.\n") + raise KeyboardInterrupt # Hack! + os.close(0) # To avoid problems with shell job control + + # always use default docroot location + cfg.options.docroot = None + + # if cvsnt isn't found, fall back to rcs + if (cfg.conf_path is None and cfg.utilities.cvsnt): + import popen + cvsnt_works = 0 + try: + fp = popen.popen(cfg.utilities.cvsnt, ['--version'], 'rt') + try: + while 1: + line = fp.readline() + if not line: + break + if string.find(line, "Concurrent Versions System (CVSNT)") >= 0: + cvsnt_works = 1 + while fp.read(4096): + pass + break + finally: + fp.close() + except: pass - print 'server stopped' + if not cvsnt_works: + cfg.utilities.cvsnt = None + + ViewVCHTTPServer(host, port, callback).serve_until_quit() + except (KeyboardInterrupt, select.error): + pass + print 'server stopped' def handle_config(config_file): global cfg @@ -346,337 +430,450 @@ # --- graphical interface: -------------------------------------------------- def nogui(missing_module): - sys.stderr.write( - "Sorry! Your Python was compiled without the %s module"%missing_module+ - " enabled.\nI'm unable to run the GUI part. Please omit the '-g'\n"+ - "and '--gui' options or install another Python interpreter.\n") - raise SystemExit, 1 + sys.stderr.write("""\ +Sorry! Your Python was compiled without the %s module enabled. +I'm unable to run the GUI part. Please omit the '-g' and '--gui' options, +or install another Python interpreter. +""" % (missing_module)) + raise SystemExit, 1 def gui(host, port): - """Graphical interface (starts web server and pops up a control window).""" - class GUI: - def __init__(self, window, host, port): - self.window = window - self.server = None - self.scanner = None - - try: - import Tkinter - except ImportError: - nogui("Tkinter") - - self.server_frm = Tkinter.Frame(window) - self.title_lbl = Tkinter.Label(self.server_frm, - text='Starting server...\n ') - self.open_btn = Tkinter.Button(self.server_frm, - text='open browser', command=self.open, state='disabled') - self.quit_btn = Tkinter.Button(self.server_frm, - text='quit serving', command=self.quit, state='disabled') - - - self.window.title('ViewVC standalone') - self.window.protocol('WM_DELETE_WINDOW', self.quit) - self.title_lbl.pack(side='top', fill='x') - self.open_btn.pack(side='left', fill='x', expand=1) - self.quit_btn.pack(side='right', fill='x', expand=1) - - # Early loading of configuration here. Used to - # allow tinkering with configuration settings through the gui: - handle_config(options.config_file) - if not LIBRARY_DIR: - cfg.options.cvsgraph_conf = "../cgi/cvsgraph.conf.dist" - - self.options_frm = Tkinter.Frame(window) - - # cvsgraph toggle: - self.cvsgraph_ivar = Tkinter.IntVar() - self.cvsgraph_ivar.set(cfg.options.use_cvsgraph) - self.cvsgraph_toggle = Tkinter.Checkbutton(self.options_frm, - text="enable cvsgraph (needs binary)", var=self.cvsgraph_ivar, - command=self.toggle_use_cvsgraph) - self.cvsgraph_toggle.pack(side='top', anchor='w') - - # show_subdir_lastmod toggle: - self.subdirmod_ivar = Tkinter.IntVar() - self.subdirmod_ivar.set(cfg.options.show_subdir_lastmod) - self.subdirmod_toggle = Tkinter.Checkbutton(self.options_frm, - text="show subdir last mod (dir view)", var=self.subdirmod_ivar, - command=self.toggle_subdirmod) - self.subdirmod_toggle.pack(side='top', anchor='w') - - # use_re_search toggle: - self.useresearch_ivar = Tkinter.IntVar() - self.useresearch_ivar.set(cfg.options.use_re_search) - self.useresearch_toggle = Tkinter.Checkbutton(self.options_frm, - text="allow regular expr search", var=self.useresearch_ivar, - command=self.toggle_useresearch) - self.useresearch_toggle.pack(side='top', anchor='w') - - # use_localtime toggle: - self.use_localtime_ivar = Tkinter.IntVar() - self.use_localtime_ivar.set(cfg.options.use_localtime) - self.use_localtime_toggle = Tkinter.Checkbutton(self.options_frm, - text="use localtime (instead of UTC)", - var=self.use_localtime_ivar, - command=self.toggle_use_localtime) - self.use_localtime_toggle.pack(side='top', anchor='w') - - # log_pagesize integer var: - self.log_pagesize_lbl = Tkinter.Label(self.options_frm, - text='Paging (number of items per log page, 0 disables):') - self.log_pagesize_lbl.pack(side='top', anchor='w') - self.log_pagesize_ivar = Tkinter.IntVar() - self.log_pagesize_ivar.set(cfg.options.log_pagesize) - self.log_pagesize_entry = Tkinter.Entry(self.options_frm, - width=10, textvariable=self.log_pagesize_ivar) - self.log_pagesize_entry.bind('', self.set_log_pagesize) - self.log_pagesize_entry.pack(side='top', anchor='w') - - # dir_pagesize integer var: - self.dir_pagesize_lbl = Tkinter.Label(self.options_frm, - text='Paging (number of items per dir page, 0 disables):') - self.dir_pagesize_lbl.pack(side='top', anchor='w') - self.dir_pagesize_ivar = Tkinter.IntVar() - self.dir_pagesize_ivar.set(cfg.options.dir_pagesize) - self.dir_pagesize_entry = Tkinter.Entry(self.options_frm, - width=10, textvariable=self.dir_pagesize_ivar) - self.dir_pagesize_entry.bind('', self.set_dir_pagesize) - self.dir_pagesize_entry.pack(side='top', anchor='w') - - # directory view template: - self.dirtemplate_lbl = Tkinter.Label(self.options_frm, - text='Choose HTML Template for the Directory pages:') - self.dirtemplate_lbl.pack(side='top', anchor='w') - self.dirtemplate_svar = Tkinter.StringVar() - self.dirtemplate_svar.set(cfg.templates.directory) - self.dirtemplate_entry = Tkinter.Entry(self.options_frm, - width = 40, textvariable=self.dirtemplate_svar) - self.dirtemplate_entry.bind('', self.set_templates_directory) - self.dirtemplate_entry.pack(side='top', anchor='w') - self.templates_dir = Tkinter.Radiobutton(self.options_frm, - text="directory.ezt", value="templates/directory.ezt", - var=self.dirtemplate_svar, command=self.set_templates_directory) - self.templates_dir.pack(side='top', anchor='w') - self.templates_dir_alt = Tkinter.Radiobutton(self.options_frm, - text="dir_alternate.ezt", value="templates/dir_alternate.ezt", - var=self.dirtemplate_svar, command=self.set_templates_directory) - self.templates_dir_alt.pack(side='top', anchor='w') - - # log view template: - self.logtemplate_lbl = Tkinter.Label(self.options_frm, - text='Choose HTML Template for the Log pages:') - self.logtemplate_lbl.pack(side='top', anchor='w') - self.logtemplate_svar = Tkinter.StringVar() - self.logtemplate_svar.set(cfg.templates.log) - self.logtemplate_entry = Tkinter.Entry(self.options_frm, - width = 40, textvariable=self.logtemplate_svar) - self.logtemplate_entry.bind('', self.set_templates_log) - self.logtemplate_entry.pack(side='top', anchor='w') - self.templates_log = Tkinter.Radiobutton(self.options_frm, - text="log.ezt", value="templates/log.ezt", - var=self.logtemplate_svar, command=self.set_templates_log) - self.templates_log.pack(side='top', anchor='w') - self.templates_log_table = Tkinter.Radiobutton(self.options_frm, - text="log_table.ezt", value="templates/log_table.ezt", - var=self.logtemplate_svar, command=self.set_templates_log) - self.templates_log_table.pack(side='top', anchor='w') - - # query view template: - self.querytemplate_lbl = Tkinter.Label(self.options_frm, - text='Template for the database query page:') - self.querytemplate_lbl.pack(side='top', anchor='w') - self.querytemplate_svar = Tkinter.StringVar() - self.querytemplate_svar.set(cfg.templates.query) - self.querytemplate_entry = Tkinter.Entry(self.options_frm, - width = 40, textvariable=self.querytemplate_svar) - self.querytemplate_entry.bind('', self.set_templates_query) - self.querytemplate_entry.pack(side='top', anchor='w') - self.templates_query = Tkinter.Radiobutton(self.options_frm, - text="query.ezt", value="templates/query.ezt", - var=self.querytemplate_svar, command=self.set_templates_query) - self.templates_query.pack(side='top', anchor='w') - - # pack and set window manager hints: - self.server_frm.pack(side='top', fill='x') - self.options_frm.pack(side='top', fill='x') - - self.window.update() - self.minwidth = self.window.winfo_width() - self.minheight = self.window.winfo_height() - self.expanded = 0 - self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight)) - self.window.wm_minsize(self.minwidth, self.minheight) - - try: - import threading - except ImportError: - nogui("thread") - threading.Thread(target=serve, - args=(host, port, self.ready)).start() - - def toggle_use_cvsgraph(self, event=None): - cfg.options.use_cvsgraph = self.cvsgraph_ivar.get() - - def toggle_use_localtime(self, event=None): - cfg.options.use_localtime = self.use_localtime_ivar.get() - - def toggle_subdirmod(self, event=None): - cfg.options.show_subdir_lastmod = self.subdirmod_ivar.get() - - def toggle_useresearch(self, event=None): - cfg.options.use_re_search = self.useresearch_ivar.get() - - def set_log_pagesize(self, event=None): - cfg.options.log_pagesize = self.log_pagesize_ivar.get() - - def set_dir_pagesize(self, event=None): - cfg.options.dir_pagesize = self.dir_pagesize_ivar.get() - - def set_templates_log(self, event=None): - cfg.templates.log = self.logtemplate_svar.get() - - def set_templates_directory(self, event=None): - cfg.templates.directory = self.dirtemplate_svar.get() - - def set_templates_query(self, event=None): - cfg.templates.query = self.querytemplate_svar.get() - - def ready(self, server): - """used as callback parameter to the serve() function""" - self.server = server - self.title_lbl.config( - text='ViewVC standalone server at\n' + server.url) - self.open_btn.config(state='normal') - self.quit_btn.config(state='normal') - - def open(self, event=None, url=None): - """opens a browser window on the local machine""" - url = url or self.server.url - try: - import webbrowser - webbrowser.open(url) - except ImportError: # pre-webbrowser.py compatibility - if sys.platform == 'win32': - os.system('start "%s"' % url) - elif sys.platform == 'mac': - try: - import ic - ic.launchurl(url) - except ImportError: pass - else: - rc = os.system('netscape -remote "openURL(%s)" &' % url) - if rc: os.system('netscape "%s" &' % url) - - def quit(self, event=None): - if self.server: - self.server.quit = 1 - self.window.quit() - - import Tkinter - try: - gui = GUI(Tkinter.Tk(), host, port) - Tkinter.mainloop() - except KeyboardInterrupt: - pass + """Graphical interface (starts web server and pops up a control window).""" + class GUI: + def __init__(self, window, host, port): + self.window = window + self.server = None + self.scanner = None + + try: + import Tkinter + except ImportError: + nogui("Tkinter") + + self.server_frm = Tkinter.Frame(window) + self.title_lbl = Tkinter.Label(self.server_frm, + text='Starting server...\n ') + self.open_btn = Tkinter.Button(self.server_frm, + text='open browser', + command=self.open, + state='disabled') + self.quit_btn = Tkinter.Button(self.server_frm, + text='quit serving', + command=self.quit, + state='disabled') + + self.window.title('ViewVC standalone') + self.window.protocol('WM_DELETE_WINDOW', self.quit) + self.title_lbl.pack(side='top', fill='x') + self.open_btn.pack(side='left', fill='x', expand=1) + self.quit_btn.pack(side='right', fill='x', expand=1) + + # Early loading of configuration here. Used to + # allow tinkering with configuration settings through the gui: + handle_config(options.config_file) + if not LIBRARY_DIR: + cfg.options.cvsgraph_conf = "../cgi/cvsgraph.conf.dist" + + self.options_frm = Tkinter.Frame(window) + + # cvsgraph toggle: + self.cvsgraph_ivar = Tkinter.IntVar() + self.cvsgraph_ivar.set(cfg.options.use_cvsgraph) + self.cvsgraph_toggle = \ + Tkinter.Checkbutton(self.options_frm, + text="enable cvsgraph (needs binary)", + var=self.cvsgraph_ivar, + command=self.toggle_use_cvsgraph) + self.cvsgraph_toggle.pack(side='top', anchor='w') + + # show_subdir_lastmod toggle: + self.subdirmod_ivar = Tkinter.IntVar() + self.subdirmod_ivar.set(cfg.options.show_subdir_lastmod) + self.subdirmod_toggle = \ + Tkinter.Checkbutton(self.options_frm, + text="show subdir last mod (dir view)", + var=self.subdirmod_ivar, + command=self.toggle_subdirmod) + self.subdirmod_toggle.pack(side='top', anchor='w') + + # use_re_search toggle: + self.useresearch_ivar = Tkinter.IntVar() + self.useresearch_ivar.set(cfg.options.use_re_search) + self.useresearch_toggle = \ + Tkinter.Checkbutton(self.options_frm, + text="allow regular expr search", + var=self.useresearch_ivar, + command=self.toggle_useresearch) + self.useresearch_toggle.pack(side='top', anchor='w') + + # use_localtime toggle: + self.use_localtime_ivar = Tkinter.IntVar() + self.use_localtime_ivar.set(cfg.options.use_localtime) + self.use_localtime_toggle = \ + Tkinter.Checkbutton(self.options_frm, + text="use localtime (instead of UTC)", + var=self.use_localtime_ivar, + command=self.toggle_use_localtime) + self.use_localtime_toggle.pack(side='top', anchor='w') + + # log_pagesize integer var: + self.log_pagesize_lbl = \ + Tkinter.Label(self.options_frm, + text='number of items per log page (0 disables):') + self.log_pagesize_lbl.pack(side='top', anchor='w') + self.log_pagesize_ivar = Tkinter.IntVar() + self.log_pagesize_ivar.set(cfg.options.log_pagesize) + self.log_pagesize_entry = \ + Tkinter.Entry(self.options_frm, + width=10, + textvariable=self.log_pagesize_ivar) + self.log_pagesize_entry.bind('', self.set_log_pagesize) + self.log_pagesize_entry.pack(side='top', anchor='w') + + # dir_pagesize integer var: + self.dir_pagesize_lbl = \ + Tkinter.Label(self.options_frm, + text='number of items per dir page (0 disables):') + self.dir_pagesize_lbl.pack(side='top', anchor='w') + self.dir_pagesize_ivar = Tkinter.IntVar() + self.dir_pagesize_ivar.set(cfg.options.dir_pagesize) + self.dir_pagesize_entry = \ + Tkinter.Entry(self.options_frm, + width=10, + textvariable=self.dir_pagesize_ivar) + self.dir_pagesize_entry.bind('', self.set_dir_pagesize) + self.dir_pagesize_entry.pack(side='top', anchor='w') + + # directory view template: + self.dirtemplate_lbl = \ + Tkinter.Label(self.options_frm, + text='Choose HTML Template for the Directory pages:') + self.dirtemplate_lbl.pack(side='top', anchor='w') + self.dirtemplate_svar = Tkinter.StringVar() + self.dirtemplate_svar.set(cfg.templates.directory) + self.dirtemplate_entry = \ + Tkinter.Entry(self.options_frm, + width=40, + textvariable=self.dirtemplate_svar) + self.dirtemplate_entry.bind('', self.set_templates_directory) + self.dirtemplate_entry.pack(side='top', anchor='w') + self.templates_dir = \ + Tkinter.Radiobutton(self.options_frm, + text="directory.ezt", + value="templates/directory.ezt", + var=self.dirtemplate_svar, + command=self.set_templates_directory) + self.templates_dir.pack(side='top', anchor='w') + self.templates_dir_alt = \ + Tkinter.Radiobutton(self.options_frm, + text="dir_alternate.ezt", + value="templates/dir_alternate.ezt", + var=self.dirtemplate_svar, + command=self.set_templates_directory) + self.templates_dir_alt.pack(side='top', anchor='w') + + # log view template: + self.logtemplate_lbl = \ + Tkinter.Label(self.options_frm, + text='Choose HTML Template for the Log pages:') + self.logtemplate_lbl.pack(side='top', anchor='w') + self.logtemplate_svar = Tkinter.StringVar() + self.logtemplate_svar.set(cfg.templates.log) + self.logtemplate_entry = \ + Tkinter.Entry(self.options_frm, + width=40, + textvariable=self.logtemplate_svar) + self.logtemplate_entry.bind('', self.set_templates_log) + self.logtemplate_entry.pack(side='top', anchor='w') + self.templates_log = \ + Tkinter.Radiobutton(self.options_frm, + text="log.ezt", + value="templates/log.ezt", + var=self.logtemplate_svar, + command=self.set_templates_log) + self.templates_log.pack(side='top', anchor='w') + self.templates_log_table = \ + Tkinter.Radiobutton(self.options_frm, + text="log_table.ezt", + value="templates/log_table.ezt", + var=self.logtemplate_svar, + command=self.set_templates_log) + self.templates_log_table.pack(side='top', anchor='w') + + # query view template: + self.querytemplate_lbl = \ + Tkinter.Label(self.options_frm, + text='Template for the database query page:') + self.querytemplate_lbl.pack(side='top', anchor='w') + self.querytemplate_svar = Tkinter.StringVar() + self.querytemplate_svar.set(cfg.templates.query) + self.querytemplate_entry = \ + Tkinter.Entry(self.options_frm, + width=40, + textvariable=self.querytemplate_svar) + self.querytemplate_entry.bind('', self.set_templates_query) + self.querytemplate_entry.pack(side='top', anchor='w') + self.templates_query = \ + Tkinter.Radiobutton(self.options_frm, + text="query.ezt", + value="templates/query.ezt", + var=self.querytemplate_svar, + command=self.set_templates_query) + self.templates_query.pack(side='top', anchor='w') + + # pack and set window manager hints: + self.server_frm.pack(side='top', fill='x') + self.options_frm.pack(side='top', fill='x') + + self.window.update() + self.minwidth = self.window.winfo_width() + self.minheight = self.window.winfo_height() + self.expanded = 0 + self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight)) + self.window.wm_minsize(self.minwidth, self.minheight) + + try: + import threading + except ImportError: + nogui("thread") + threading.Thread(target=serve, args=(host, port, self.ready)).start() + + def toggle_use_cvsgraph(self, event=None): + cfg.options.use_cvsgraph = self.cvsgraph_ivar.get() + + def toggle_use_localtime(self, event=None): + cfg.options.use_localtime = self.use_localtime_ivar.get() + + def toggle_subdirmod(self, event=None): + cfg.options.show_subdir_lastmod = self.subdirmod_ivar.get() + + def toggle_useresearch(self, event=None): + cfg.options.use_re_search = self.useresearch_ivar.get() + + def set_log_pagesize(self, event=None): + cfg.options.log_pagesize = self.log_pagesize_ivar.get() + + def set_dir_pagesize(self, event=None): + cfg.options.dir_pagesize = self.dir_pagesize_ivar.get() + + def set_templates_log(self, event=None): + cfg.templates.log = self.logtemplate_svar.get() + + def set_templates_directory(self, event=None): + cfg.templates.directory = self.dirtemplate_svar.get() + + def set_templates_query(self, event=None): + cfg.templates.query = self.querytemplate_svar.get() + + def ready(self, server): + """used as callback parameter to the serve() function""" + self.server = server + self.title_lbl.config(text='ViewVC standalone server at\n' + server.url) + self.open_btn.config(state='normal') + self.quit_btn.config(state='normal') + + def open(self, event=None, url=None): + """opens a browser window on the local machine""" + url = url or self.server.url + try: + import webbrowser + webbrowser.open(url) + except ImportError: # pre-webbrowser.py compatibility + if sys.platform == 'win32': + os.system('start "%s"' % url) + elif sys.platform == 'mac': + try: + import ic + ic.launchurl(url) + except ImportError: pass + else: + rc = os.system('netscape -remote "openURL(%s)" &' % url) + if rc: + os.system('netscape "%s" &' % url) + + def quit(self, event=None): + if self.server: + self.server.quit = 1 + self.window.quit() + + import Tkinter + try: + gui = GUI(Tkinter.Tk(), host, port) + Tkinter.mainloop() + except KeyboardInterrupt: + pass # --- command-line interface: ---------------------------------------------- -def cli(argv): - """Command-line interface (looks at argv to decide what to do).""" - import getopt - class BadUsage(Exception): pass - try: - opts, args = getopt.getopt(argv[1:], 'gdc:p:r:h:s:', - ['gui', 'daemon', 'config-file=', 'host=', - 'port=', 'repository=', 'script-alias=']) - for opt, val in opts: - if opt in ('-g', '--gui'): - options.start_gui = 1 - elif opt in ('-r', '--repository'): - if options.repositories: # option may be used more than once: - num = len(options.repositories.keys())+1 - symbolic_name = "Repository"+str(num) - options.repositories[symbolic_name] = val - else: - options.repositories["Development"] = val - elif opt in ('-d', '--daemon'): - options.daemon = 1 - elif opt in ('-p', '--port'): - try: - options.port = int(val) - except ValueError: - raise BadUsage, "Port '%s' is not a valid port number" \ - % (val) - elif opt in ('-h', '--host'): - options.host = val - elif opt in ('-s', '--script-alias'): - options.script_alias = \ - string.join(filter(None, string.split(val, '/')), '/') - elif opt in ('-c', '--config-file'): - options.config_file = val - if options.start_gui and options.config_file: - raise BadUsage, "--config-file option is not valid in GUI mode." - if not options.start_gui and not options.port: - raise BadUsage, "You must supply a valid port, or run in GUI mode." - if options.daemon: - pid = os.fork() - if pid != 0: - sys.exit() - if options.start_gui: - gui(options.host, options.port) - return - elif options.port: - def ready(server): - print 'server ready at %s%s' % (server.url, - options.script_alias) - serve(options.host, options.port, ready) - return - except (getopt.error, BadUsage), err: - cmd = os.path.basename(sys.argv[0]) - port = options.port - host = options.host - script_alias = options.script_alias - if str(err): - sys.stderr.write("ERROR: %s\n\n" % (str(err))) - sys.stderr.write("""Usage: %(cmd)s [OPTIONS] +def usage(): + clean_options = Options() + cmd = os.path.basename(sys.argv[0]) + port = clean_options.port + host = clean_options.host + script_alias = clean_options.script_alias + sys.stderr.write("""Usage: %(cmd)s [OPTIONS] -Run a simple, standalone HTTP server configured to serve up ViewVC -requests. +Run a simple, standalone HTTP server configured to serve up ViewVC requests. Options: - --config-file=PATH (-c) Use the file at PATH as the ViewVC configuration - file. If not specified, ViewVC will try to use - the configuration file in its installation tree; - otherwise, built-in default values are used. - (Not valid in GUI mode.) + --config-file=FILE (-c) Read configuration options from FILE. If not + specified, ViewVC will look for a configuration + file in its installation tree, falling back to + built-in default values. (Not valid in GUI mode.) --daemon (-d) Background the server process. + + --gui (-g) Pop up a graphical configuration interface. + Requires a valid X11 display connection. + + --help Show this usage message and exit. - --host=HOST (-h) Start the server listening on HOST. You need - to provide the hostname if you want to - access the standalone server from a remote - machine. [default: %(host)s] + --host=HOSTNAME (-h) Listen on HOSTNAME. Required for access from a + remote machine. [default: %(host)s] + + --htpasswd-file=FILE Authenticate incoming requests, validating against + against FILE, which is an Apache HTTP Server + htpasswd file. (CRYPT only; no DIGEST support.) - --port=PORT (-p) Start the server on the given PORT. - [default: %(port)d] + --port=PORT (-p) Listen on PORT. [default: %(port)d] - --repository=PATH (-r) Serve up the Subversion or CVS repository located + --repository=PATH (-r) Serve the Subversion or CVS repository located at PATH. This option may be used more than once. - --script-alias=PATH (-s) Specify the ScriptAlias, the artificial path - location that at which ViewVC appears to be - located. For example, if your ScriptAlias is - "cgi-bin/viewvc", then ViewVC will be accessible - at "http://%(host)s:%(port)s/cgi-bin/viewvc". + --script-alias=PATH (-s) Use PATH as the virtual script location (similar + to Apache HTTP Server's ScriptAlias directive). + For example, "--script-alias=repo/view" will serve + ViewVC at "http://HOSTNAME:PORT/repo/view". [default: %(script_alias)s] - - --gui (-g) Pop up a graphical interface for serving and - testing ViewVC. NOTE: this requires a valid - X11 display connection. """ % locals()) + sys.exit(0) + + +def badusage(errstr): + cmd = os.path.basename(sys.argv[0]) + sys.stderr.write("ERROR: %s\n\n" + "Try '%s --help' for detailed usage information.\n" + % (errstr, cmd)) + sys.exit(1) + + +def main(argv): + """Command-line interface (looks at argv to decide what to do).""" + import getopt + + short_opts = string.join(['c:', + 'd', + 'g', + 'h:', + 'p:', + 'r:', + 's:', + ], '') + long_opts = ['daemon', + 'config-file=', + 'gui', + 'help', + 'host=', + 'htpasswd-file=', + 'port=', + 'repository=', + 'script-alias=', + ] + + opt_daemon = 0 + opt_gui = 0 + opt_host = None + opt_port = None + opt_htpasswd_file = None + opt_config_file = None + opt_script_alias = None + opt_repositories = [] + + # Parse command-line options. + try: + opts, args = getopt.getopt(argv[1:], short_opts, long_opts) + for opt, val in opts: + if opt in ['--help']: + usage() + elif opt in ['-g', '--gui']: + opt_gui = 1 + elif opt in ['-r', '--repository']: # may be used more than once + opt_repositories.append(val) + elif opt in ['-d', '--daemon']: + opt_daemon = 1 + elif opt in ['-p', '--port']: + opt_port = val + elif opt in ['-h', '--host']: + opt_host = val + elif opt in ['-s', '--script-alias']: + opt_script_alias = val + elif opt in ['-c', '--config-file']: + opt_config_file = val + elif opt in ['--htpasswd-file']: + opt_htpasswd_file = val + except getopt.error, err: + badusage(str(err)) + + # Validate options that need validating. + class BadUsage(Exception): pass + try: + if opt_port is not None: + try: + options.port = int(opt_port) + except ValueError: + raise BadUsage("Port '%s' is not a valid port number" % (opt_port)) + if not options.port: + raise BadUsage("You must supply a valid port.") + if opt_htpasswd_file is not None: + if not os.path.isfile(opt_htpasswd_file): + raise BadUsage("'%s' does not appear to be a valid htpasswd file." + % (opt_htpasswd_file)) + if not has_crypt: + raise BadUsage("Unable to locate suitable `crypt' module for use " + "with --htpasswd-file option. If your Python " + "distribution does not include this module (as is " + "the case on many non-Unix platforms), consider " + "installing the `fcrypt' module instead (see " + "http://carey.geek.nz/code/python-fcrypt/).") + options.htpasswd_file = opt_htpasswd_file + if opt_config_file is not None: + if not os.path.isfile(opt_config_file): + raise BadUsage("'%s' does not appear to be a valid configuration file." + % (opt_config_file)) + options.config_file = opt_config_file + if opt_host is not None: + options.host = opt_host + if opt_script_alias is not None: + options.script_alias = string.join(filter(None, + string.split(opt_script_alias, + '/')), + '/') + for repository in opt_repositories: + if not options.repositories.has_key('Development'): + rootname = 'Development' + else: + rootname = 'Repository%d' % (len(options.repositories.keys()) + 1) + options.repositories[rootname] = repository + except BadUsage, err: + badusage(str(err)) + + # Fork if we're in daemon mode. + if opt_daemon: + pid = os.fork() + if pid != 0: + sys.exit() + + # Finaly, start the server. + if opt_gui: + gui(options.host, options.port) + else: + def ready(server): + print 'server ready at %s%s' % (server.url, options.script_alias) + serve(options.host, options.port, ready) + if __name__ == '__main__': - options = Options() - cli(sys.argv) + options = Options() + main(sys.argv) diff -Nru viewvc-1.1.5/bin/svndbadmin viewvc-1.1.23/bin/svndbadmin --- viewvc-1.1.5/bin/svndbadmin 2009-06-08 15:53:47.000000000 +0000 +++ viewvc-1.1.23/bin/svndbadmin 2014-05-02 15:01:43.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*-python-*- # -# Copyright (C) 2004-2008 The ViewCVS Group. All Rights Reserved. +# Copyright (C) 2004-2014 The ViewCVS Group. All Rights Reserved. # Copyright (C) 2004-2007 James Henstridge # # By using this file, you agree to the terms and conditions set forth in @@ -153,7 +153,7 @@ fsroot = self._get_root_for_rev(rev) # find changes in the revision - editor = svn.repos.RevisionChangeCollector(repo.fs, rev) + editor = svn.repos.ChangeCollector(repo.fs, fsroot) e_ptr, e_baton = svn.delta.make_editor(editor) svn.repos.svn_repos_replay(fsroot, e_ptr, e_baton) @@ -164,21 +164,33 @@ continue # deal with the change types we handle + action = None base_root = None + base_path = change.base_path if change.base_path: base_root = self._get_root_for_rev(change.base_rev) - - if not change.path: + + # figure out what kind of change this is, and get a diff + # object for it. note that prior to 1.4 Subversion's + # bindings didn't give us change.action, but that's okay + # because back then deleted paths always had a change.path + # of None. + if hasattr(change, 'action') \ + and change.action == svn.repos.CHANGE_ACTION_DELETE: + action = 'remove' + elif not change.path: action = 'remove' elif change.added: action = 'add' else: action = 'change' - diffobj = svn.fs.FileDiff(base_root and base_root or None, - base_root and change.base_path or None, - change.path and fsroot or None, - change.path and change.path or None) + if action == 'remove': + diffobj = svn.fs.FileDiff(base_root, base_path, None, None) + else: + diffobj = svn.fs.FileDiff(base_root, base_path, + fsroot, change.path) + diff_fp = diffobj.get_pipe() plus, minus = _get_diff_counts(diff_fp) self.changes.append((path, action, plus, minus)) @@ -242,6 +254,7 @@ cfg = viewvc.load_config(CONF_PATHNAME) db = cvsdb.ConnectDatabase(cfg) + # Purge what must be purged. if command in ('rebuild', 'purge'): if verbose: print "Purging commit info for repository root `%s'" % repository @@ -252,18 +265,24 @@ sys.stderr.write("ERROR: " + str(e) + "\n") sys.exit(1) - repo = SvnRepo(repository) - if command == 'rebuild' or (command == 'update' and not revs): - for rev in range(repo.rev_max+1): - handle_revision(db, command, repo, rev, verbose) - elif command == 'update': - if revs[0] is None: - revs[0] = repo.rev_max - if revs[1] is None: - revs[1] = repo.rev_max - revs.sort() - for rev in range(revs[0], revs[1]+1): - handle_revision(db, command, repo, rev, verbose, force) + # Record what must be recorded. + if command in ('rebuild', 'update'): + if not os.path.exists(repository): + sys.stderr.write('ERROR: could not find repository %s\n' + % (repository)) + sys.exit(1) + repo = SvnRepo(repository) + if command == 'rebuild' or (command == 'update' and not revs): + for rev in range(repo.rev_max+1): + handle_revision(db, command, repo, rev, verbose) + elif command == 'update': + if revs[0] is None: + revs[0] = repo.rev_max + if revs[1] is None: + revs[1] = repo.rev_max + revs.sort() + for rev in range(revs[0], revs[1]+1): + handle_revision(db, command, repo, rev, verbose, force) def _rev2int(r): if r == 'HEAD': @@ -281,7 +300,7 @@ located at REPOS-PATH. Usage: 1. %s [-v] rebuild REPOS-PATH - 2. %s [-v] update REPOS-PATH [REV:[REV2]] [--force] + 2. %s [-v] update REPOS-PATH [REV[:REV2]] [--force] 3. %s [-v] purge REPOS-PATH 1. Rebuild the commit database information for the repository located @@ -330,12 +349,6 @@ sys.stderr.write('ERROR: unknown command %s\n' % command) usage() - repository = args[2] - if not os.path.exists(repository): - sys.stderr.write('ERROR: could not find repository %s\n' % args[2]) - usage() - repository = vclib.svn.canonicalize_rootpath(repository) - revs = [] if len(sys.argv) > 3: if command == 'rebuild': @@ -358,6 +371,7 @@ rev = None try: + repository = vclib.svn.canonicalize_rootpath(args[2]) repository = cvsdb.CleanRepository(os.path.abspath(repository)) main(command, repository, revs, verbose, force) except KeyboardInterrupt: diff -Nru viewvc-1.1.5/bin/wsgi/query.fcgi viewvc-1.1.23/bin/wsgi/query.fcgi --- viewvc-1.1.5/bin/wsgi/query.fcgi 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/bin/wsgi/query.fcgi 2014-05-02 15:01:43.000000000 +0000 @@ -0,0 +1,54 @@ +#!/usr/bin/python +# -*-python-*- +# +# Copyright (C) 1999-2014 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/ +# +# ----------------------------------------------------------------------- +# +# viewvc: View CVS/SVN repositories via a web browser +# +# ----------------------------------------------------------------------- +# +# This is a fcgi entry point for the query ViewVC app. It's appropriate +# for use with mod_fcgid and flup. It defines a single application function +# that is a valid fcgi entry point. +# +# mod_fcgid: http://httpd.apache.org/mod_fcgid/ +# flup: +# http://pypi.python.org/pypi/flup +# http://trac.saddi.com/flup +# +# ----------------------------------------------------------------------- + +import sys, os + +LIBRARY_DIR = None +CONF_PATHNAME = None + +if LIBRARY_DIR: + sys.path.insert(0, LIBRARY_DIR) +else: + sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], + "../../../lib"))) + +import sapi +import viewvc +import query +from flup.server import fcgi + +def application(environ, start_response): + server = sapi.WsgiServer(environ, start_response) + cfg = viewvc.load_config(CONF_PATHNAME, server) + viewvc_base_url = cfg.query.viewvc_base_url + if viewvc_base_url is None: + viewvc_base_url = "viewvc.fcgi" + query.main(server, cfg, viewvc_base_url) + return [] + +fcgi.WSGIServer(application).run() diff -Nru viewvc-1.1.5/bin/wsgi/query.wsgi viewvc-1.1.23/bin/wsgi/query.wsgi --- viewvc-1.1.5/bin/wsgi/query.wsgi 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/bin/wsgi/query.wsgi 2014-05-02 15:01:43.000000000 +0000 @@ -0,0 +1,45 @@ +# -*-python-*- +# +# Copyright (C) 1999-2014 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/ +# +# ----------------------------------------------------------------------- +# +# viewvc: View CVS/SVN repositories via a web browser +# +# ----------------------------------------------------------------------- +# +# This is a wsgi entry point for the query ViewVC app. It's appropriate +# for use with mod_wsgi. It defines a single application function that +# is a valid wsgi entry point. +# +# ----------------------------------------------------------------------- + +import sys, os + +LIBRARY_DIR = None +CONF_PATHNAME = None + +if LIBRARY_DIR: + sys.path.insert(0, LIBRARY_DIR) +else: + sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], + "../../../lib"))) + +import sapi +import viewvc +import query + +def application(environ, start_response): + server = sapi.WsgiServer(environ, start_response) + cfg = viewvc.load_config(CONF_PATHNAME, server) + viewvc_base_url = cfg.query.viewvc_base_url + if viewvc_base_url is None: + viewvc_base_url = "viewvc.wsgi" + query.main(server, cfg, viewvc_base_url) + return [] diff -Nru viewvc-1.1.5/bin/wsgi/viewvc.fcgi viewvc-1.1.23/bin/wsgi/viewvc.fcgi --- viewvc-1.1.5/bin/wsgi/viewvc.fcgi 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/bin/wsgi/viewvc.fcgi 2014-05-02 15:01:43.000000000 +0000 @@ -0,0 +1,50 @@ +#!/usr/bin/python +# -*-python-*- +# +# Copyright (C) 1999-2014 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/ +# +# ----------------------------------------------------------------------- +# +# viewvc: View CVS/SVN repositories via a web browser +# +# ----------------------------------------------------------------------- +# +# This is a fcgi entry point for the main ViewVC app. It's appropriate +# for use with mod_fcgid and flup. It defines a single application function +# that is a valid fcgi entry point. +# +# mod_fcgid: http://httpd.apache.org/mod_fcgid/ +# flup: +# http://pypi.python.org/pypi/flup +# http://trac.saddi.com/flup +# +# ----------------------------------------------------------------------- + +import sys, os + +LIBRARY_DIR = None +CONF_PATHNAME = None + +if LIBRARY_DIR: + sys.path.insert(0, LIBRARY_DIR) +else: + sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], + "../../../lib"))) + +import sapi +import viewvc +from flup.server import fcgi + +def application(environ, start_response): + server = sapi.WsgiServer(environ, start_response) + cfg = viewvc.load_config(CONF_PATHNAME, server) + viewvc.main(server, cfg) + return [] + +fcgi.WSGIServer(application).run() diff -Nru viewvc-1.1.5/bin/wsgi/viewvc.wsgi viewvc-1.1.23/bin/wsgi/viewvc.wsgi --- viewvc-1.1.5/bin/wsgi/viewvc.wsgi 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/bin/wsgi/viewvc.wsgi 2014-05-02 15:01:43.000000000 +0000 @@ -0,0 +1,41 @@ +# -*-python-*- +# +# Copyright (C) 1999-2014 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/ +# +# ----------------------------------------------------------------------- +# +# viewvc: View CVS/SVN repositories via a web browser +# +# ----------------------------------------------------------------------- +# +# This is a wsgi entry point for the main ViewVC app. It's appropriate +# for use with mod_wsgi. It defines a single application function that +# is a valid wsgi entry point. +# +# ----------------------------------------------------------------------- + +import sys, os + +LIBRARY_DIR = None +CONF_PATHNAME = None + +if LIBRARY_DIR: + sys.path.insert(0, LIBRARY_DIR) +else: + sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], + "../../../lib"))) + +import sapi +import viewvc + +def application(environ, start_response): + server = sapi.WsgiServer(environ, start_response) + cfg = viewvc.load_config(CONF_PATHNAME, server) + viewvc.main(server, cfg) + return [] diff -Nru viewvc-1.1.5/CHANGES viewvc-1.1.23/CHANGES --- viewvc-1.1.5/CHANGES 2010-03-29 15:24:33.000000000 +0000 +++ viewvc-1.1.23/CHANGES 2014-11-05 00:14:05.000000000 +0000 @@ -1,3 +1,152 @@ +Version 1.1.23 (released 04-Nov-2014) + + * fix annotate bug triggered by files with trailing blank lines (issue #533) + * fix markup display of files with trailing blank lines (issue #533) + * add support for root-relative svnauthz access files (issue #535) + * fix cvsdb MySQL-python argument conversion error (issue #539) + * fix double-escaping of revision links (issue #541) + * fix bug that prevented mod_python 3.4+ deployment (issue #540) + +Version 1.1.22 (released 14-Jan-2014) + + * minor directory sorting logic fix (re: show_subdir_lastmod) + * fix display of show_subdir_lastmod details (issue #532) + * pay attention to chardet's detection confidence + * linkify line numbers in markup/annotate view + +Version 1.1.21 (released 13-Sep-2013) + + * fix markup/annotate exception with Python < 2.7 (issue #527) + +Version 1.1.20 (released 24-Apr-2013) + + * fix tab-to-space handling regression in markup view + * fix regression in root lookup handling (issue #526) + +Version 1.1.19 (released 22-Apr-2013) + + * improve root lookup performance (issue #523) + * new 'max_filesize_kbytes' config option and handling (issue #524) + * tarball generation improvements: + - preserve Subversion symlinks in generated tarballs (issue #487) + - reduce memory usage of tarball generation logic + - fix double compression of generated tarballs (issue #525) + * file content handling improvements: + - expanded support for encoding detection and transcoding (issue #11) + - fix tab-to-space conversion bugs in markup, annotate, and diff views + - fix handling of trailing whitespace in diff view + * add support for timestamp display in ISO8601 format (issue #46) + +Version 1.1.18 (released 28-Feb-2013) + + * fix exception raised by BDB-backed SVN repositories (issue #519) + * hide revision-less files when rcsparse is in use + * include branchpoints in branch views using rcsparse (issue #347) + * miscellaneous cvsdb improvements: + - add --port option to make-database (issue #521) + - explicitly name columns in queries (issue #522) + - update MySQL syntax to avoid discontinued "TYPE=" terms + +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) + * handle file:/// Subversion rootpaths as local roots (issue #446) + * fix bug caused by trying to case-normalize anon usernames (issue #505) + * speed up log handling by reusing tokenization results (issue #506) + * add support for custom revision log markup rules (issue #246) + +Version 1.1.13 (released 23-Jan-2012) + + * fix svndbadmin failure on deleted paths under Subversion 1.7 (issue #499) + * fix annotation of files in svn roots with non-URI-safe paths + * fix stray annotation warning in markup display of images + * more gracefully handle attempts to display binary content (issue #501) + +Version 1.1.12 (released 03-Nov-2011) + + * fix path display in patch and certain diff views (issue #485) + * fix broken cvsdb glob searching (issue 486) + * allow svn revision specifiers to have leading r's (issue #441, #448) + * allow environmental override of configuration location (issue #494) + * fix exception HTML-escaping non-string data under WSGI (issue #454) + * add links to root logs from roots view (issue #470) + * use Pygments lexer-guessing functionality (issue #495) + +Version 1.1.11 (released 17-May-2011) + + * security fix: remove user-reachable override of cvsdb row limit + * fix broken standalone.py -c and -d options handling + * add --help option to standalone.py + * fix stack trace when asked to checkout a directory (issue #478) + * improve memory usage and speed of revision log markup (issue #477) + * fix broken annotation view in CVS keyword-bearing files (issue #479) + * warn users when query results are incomplete (issue #433) + * avoid parsing errors on RCS newphrases in the admin section (issue #483) + * make rlog parsing code more robust in certain error cases (issue #444) + +Version 1.1.10 (released 15-Mar-2011) + + * fix stack trace in Subversion revision info logic (issue #475, issue #476) + +Version 1.1.9 (released 18-Feb-2011) + + * vcauth universal access determinations (issue #425) + * rework svn revision info cache for performance + * make revision log "extra pages" count configurable + * fix Subversion 1.4.x revision log compatibility code regression + * display sanitized error when authzfile is malformed + * restore markup of URLs in file contents (issue #455) + * optionally display last-committed metadata in roots view (issue #457) + +Version 1.1.8 (released 02-Dec-2010) + + * fix slowness triggered by allow_compress=1 configuration (issue #467) + * allow use of 'fcrypt' for Windows standalone.py authn support (issue #471) + * yield more useful error on directory markup/annotate request (issue #472) + +Version 1.1.7 (released 09-Sep-2010) + + * display Subversion revision properties in the revision view (issue #453) + * fix exception in 'standalone.py -r REPOS' when run without a config file + * fix standalone.py server root deployments (--script-alias='') + * add Basic authentication support to standalone.py (Unix only) (issue #49) + * fix obscure "unexpected NULL parent pool" Subversion bindings error + * enable path info / link display in remote Subversion root revision view + * fix vhost name case handling inconsistency (issue #466) + * use svn:mime-type property charset param as encoding hint + * markup Subversion revision references in log messages (issue #313) + * add rudimentary support for FastCGI-based deployments (issue #464) + * fix query script WSGI deployment + * add configuration to fix query script cross-linking to ViewVC + +Version 1.1.6 (released 02-Jun-2010) + + * add rudimentary support for WSGI-based deployments (issue #397) + * fix exception caused by trying to HTML-escape non-string data (issue #454) + * fix incorrect RSS feed Content-Type header (issue #449) + * fix RSS encoding problem (issue #451) + * allow 'svndbadmin purge' to work on missing repositories (issue #452) + Version 1.1.5 (released 29-Mar-2010) * security fix: escape user-provided search_re input to avoid XSS attack diff -Nru viewvc-1.1.5/conf/viewvc.conf.dist viewvc-1.1.23/conf/viewvc.conf.dist --- viewvc-1.1.5/conf/viewvc.conf.dist 2010-01-08 17:47:29.000000000 +0000 +++ viewvc-1.1.23/conf/viewvc.conf.dist 2014-05-07 15:06:36.000000000 +0000 @@ -86,8 +86,8 @@ ## cvs_roots: Specifies each of the CVS roots on your system and ## assigns names to them. Each root should be given by a "name: path" -## value. Multiple roots should be separated by commas and can be -## placed on separate lines. +## value (where the path is an absolute filesystem path). Multiple roots +## should be separated by commas and can be placed on separate lines. ## ## Example: ## cvs_roots = cvsroot: /opt/cvs/repos1, @@ -97,8 +97,13 @@ ## svn_roots: Specifies each of the Subversion roots (repositories) on ## your system and assigns names to them. Each root should be given by -## a "name: path" value. Multiple roots should be separated by commas -## and can be placed on separate lines. +## a "name: path" value (where the path is an absolute filesystem path). +## Multiple roots should be separated by commas and can be placed on +## separate lines. +## +## NOTE: ViewVC offers *experimental* support for displaying remote +## Subversion repositories. Simply use the repository's URL instead +## of a local filesystem path when defining the root. ## ## Example: ## svn_roots = svnrepos: /opt/svn/, @@ -106,27 +111,48 @@ ## #svn_roots = -## root_parents: Specifies a list of directories in which any number of -## repositories may reside. Rather than force you to add a new entry -## to 'cvs_roots' or 'svn_roots' each time you create a new repository, -## ViewVC rewards you for organising all your repositories under a few -## parent directories by allowing you to simply specifiy just those -## parent directories. ViewVC will then notice each repository in that -## directory as a new root whose name is the subdirectory of the parent -## path in which that repository lives. -## -## You can specify multiple parent paths separated by commas or new lines. -## -## WARNING: these names can, of course, clash with names you have -## defined in your cvs_roots or svn_roots configuration items. If this -## occurs, you can either rename the offending repository on disk, or -## grant new names to the clashing item in cvs_roots or svn_roots. -## Each parent path is processed sequentially, so repositories under -## later parent paths may override earlier ones. +## root_parents: Specifies a list of directories under which any +## number of repositories may reside. You can specify multiple root +## parents separated by commas or new lines, each of which is of the +## form "path: type" (where the type is either "cvs" or "svn", and +## the path is an absolute filesystem path). +## +## Rather than force you to add a new entry to 'cvs_roots' or +## 'svn_roots' each time you create a new repository, ViewVC rewards +## you for organizing all your repositories under a few parent +## directories by allowing you to simply tell it about those parent +## directories. ViewVC will then notice each repository of the +## specified type in that directory as a root whose name is the +## subdirectory in which that repository lives. +## +## For example, if you have three Subversion repositories located at +## /opt/svn/projects, /opt/svn/websites, and /opt/svn/devstuff, you +## could list them individually in svn_roots like so: +## +## svn_roots = projects: /opt/svn/projects, +## websites: /opt/svn/websites, +## devstuff: /opt/svn/devstuff +## +## or you could instead use the root_parents configuration option: +## +## root_parents = /opt/svn: svn +## +## The benefit of this latter approach is that, as you add new +## repositories to your /opt/svn directory, they automatically become +## available for display in ViewVC without additional configuration. +## +## WARNING: the root names derived for repositories configured via the +## root_parents option can, of course, clash with names you have +## defined in your cvs_roots or svn_roots configuration items. If +## this occurs, you can either rename the offending repository on +## disk, or grant new names to the clashing item in cvs_roots or +## svn_roots. Each parent path is processed sequentially, so the +## names of repositories under later parent paths may override earlier +## ones. ## ## Example: -## root_parents = /opt/svn : svn, -## /opt/cvs : cvs +## root_parents = /opt/svn: svn, +## /opt/cvs: cvs ## #root_parents = @@ -325,10 +351,64 @@ ## allowed_views: List the ViewVC views which are enabled. Views not ## in this comma-delited list will not be served (or, will return an ## error on attempted access). -## Possible values: "annotate", "co", "diff", "markup", "roots", "tar" +## +## Valid items for this list include: "annotate", "co", "diff", "markup", +## "roots", "tar". +## +## ----------+--------------------------------------------------------- +## VIEW | DESCRIPTION +## ----------+--------------------------------------------------------- +## annotate | The 'annotate' view shows the contents of a single +## | revision of a versioned file in exactly the same way as +## | the markup view, but with additional line-by-line +## | change attribution (the revision number, author, etc. +## | the most recent edit to that line of text as of the +## | displayed version). +## ----------+--------------------------------------------------------- +## co | The 'co' (aka "checkout" or "download") view isn't +## | really a branded view at all, but allows for direct +## | downloading of the contents of a single revision of a +## | versioned file. +## ----------+--------------------------------------------------------- +## diff | The 'diff' view displays line-based differences between +## | two revisions of a versioned file in a variety of +## | different user-selectable formats. +## ----------+--------------------------------------------------------- +## markup | The 'markup' view shows the contents of a single +## | revision of a versioned file, with syntax highlighting +## | where possible and enabled. It can also optionally +## | show change log information for that revision of the +## | file. +## ----------+--------------------------------------------------------- +## roots | The 'roots' view is a simple listing of the various +## | repositories which ViewVC has been configured to serve +## | to users. +## ----------+--------------------------------------------------------- +## tar | The 'tar' view isn't a branded view, but generates +## | a GNU Tar archive file containing a single versioned +## | directory and its contents (recursively). +## ----------+--------------------------------------------------------- ## #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 @@ -371,6 +451,26 @@ ## #mangle_email_addresses = 0 +## custom_log_formatting: Specifies mappings of regular expressions to +## substitution format strings used to URL-ize strings found in +## revision log messages. Multiple mappings (specified as +## REGEXP:FORMATSTRING) may be defined, separated by commas. +## +## NOTE: Due to a limitation of the configuration format, commas may +## not be used in the regular expression portion of each mapping. +## Commas "in the raw" may not be used in the format string portion, +## either, but you can probably use the URI-encoded form of the comma +## ("%2C") instead with no ill side-effects. If you must specify a +## colon character in either the regular expression or the format +## string, escape it with a preceding backslash ("\:"). +## +## Example: +## custom_log_formatting = +## artf[0-9]+ : http://example.com/tracker?id=\0, +## issue ([0-9]+) : http://example.com/bug?id=\1&opts=full%2csortby=id +## +#custom_log_formatting = + ## default_file_view: "log", "co", or "markup" ## Controls whether the default view for file URLs is a checkout view or ## a log view. "log" is the default for backwards compatibility with old @@ -410,6 +510,15 @@ ## #svn_ignore_mimetype = 0 +## max_filesize_kbytes: Limit ViewVC's processing of file contents in +## "markup" and "annotate" views to only those files which are smaller +## than this setting, expressed in kilobytes. Set to 0 to disable +## this safeguard. +## +## NOTE: The "co" and "tar" views are unaffected by this setting. +## +#max_filesize_kbytes = 512 + ## svn_config_dir: Path of the Subversion runtime configuration ## directory ViewVC should consult for various things, including cached ## remote authentication credentials. If unset, Subversion will use @@ -479,7 +588,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. @@ -552,6 +661,14 @@ ## #show_subdir_lastmod = 0 +## show_roots_lastmod: In the root listing view, show the most recent +## modifications made to the root. (Subversion roots only.) +## +## NOTE: Enabling this feature will significantly reduce the +## performance of the root listing view. +## +#show_roots_lastmod = 0 + ## show_logs: Show the most recent log entry in directory listings. ## #show_logs = 1 @@ -569,25 +686,35 @@ ## #use_localtime = 0 +## iso8601_dates: Display timestamps using a standard ISO-8601 format. +## +#iso8601_timestamps = 0 + ## short_log_len: The length (in characters) to which the most recent ## log entry should be truncated when shown in the directory view. ## #short_log_len = 80 ## enable_syntax_coloration: Should we colorize known file content -## syntaxes? [Requires Pygments Python module] +## syntaxes? +## +## NOTE: This feature requires the Pygments Python module +## (http://pygments.org) and works only when ViewVC can determine the +## MIME content type of the file whose contents it wishes to colorize. +## Use the 'mime_types_files' configuration option to specify MIME +## type mapping files useful for making that determination. ## #enable_syntax_coloration = 1 -## tabsize: The number of spaces into which tabstops are converted -## when viewing file contents. +## tabsize: The number of spaces into which horizontal tab characters +## are converted when viewing file contents. Set to 0 to preserve +## tab characters. ## #tabsize = 8 ## detect_encoding: Should we attempt to detect versioned file ## character encodings? [Requires 'chardet' module, and is currently -## used only by the syntax coloration logic -- if enabled -- for the -## 'markup' and 'annotate' views; see 'enable_syntax_coloration'.] +## used only for the 'markup' and 'annotate' views.] ## #detect_encoding = 0 @@ -629,6 +756,26 @@ ## #log_pagesize = 0 +## log_pagesextra: Maximum number of extra pages (based on +## log_pagesize) of revision log data to fetch and present to the user +## as additional options for display. Revision log information +## "beyond" this window is still accessible, but must be navigated to +## in multiple steps. +## +## Example: +## log_pagesize = 100 +## log_pagesextra = 3 +## +## For a versioned file with 1000 revisions, the above settings would +## present to the user the first 100 of those 1000 revisions, with +## links to three additional pages (the 200-299th revisions, 300-399th +## revisions, and 400-499th revisions) plus a link to the 500th +## revision. Following these links slides the display "window", +## showing the requested set of revisions plus links to three +## additional pages beyond those, and so on. +## +#log_pagesextra = 3 + ## limit_changes: Maximum number of changed paths shown per commit in ## the Subversion revision view and in query results. This is not a ## hard limit (the UI provides options to show all changed paths), but @@ -749,6 +896,14 @@ ## row_limit: Maximum number of rows returned by a given normal query ## to the database. ## +## NOTE: This limits the amount of data provided to ViewVC by the +## database. It is from this already-reduced data set that ViewVC +## builds the query response it presents to the user, which may or may +## not include still more limiting via the query form's 'limit' +## parameter. In other words, there is no value which the user can use +## in the query form's 'limit' parameter which will cause more data to +## be returned by the database for ViewVC to process. +## #row_limit = 1000 ## rss_row_limit: Maximum number of rows returned by a given query to @@ -756,6 +911,9 @@ ## that RSS readers tend to poll regularly for new data, you might want ## to keep this set to a conservative number.) ## +## See also the `NOTE' for the 'row_limit' option, which applies here +## as well. +## #rss_row_limit = 100 ## check_database_for_root: Check if the repository is found in the @@ -988,6 +1146,14 @@ ## #authzfile = +## root_relative_authzfile: Specifies the location of the +## authorization rules file using an path relative to the repository. +## +## Example: +## root_relative_authzfile = conf/access +## +#root_relative_authzfile = + ## force_username_case: Like the AuthzForceUsernameCase httpd.conf ## directive, set this to "upper" or "lower" to force the normalization ## to upper- or lower-case, respectively, of incoming usernames prior @@ -997,3 +1163,30 @@ #force_username_case = ##--------------------------------------------------------------------------- +[query] + +## The configuration items in this section are used exclusively by the +## 'query' script, a separate script from ViewVC itself that ships +## with ViewVC and allows for queries into the ViewVC commits +## database. If you aren't using this separate script (which was made +## largely irrelevant by the introduction of an integrated "query" +## view in ViewVC itself, or aren't using the ViewVC commits database +## functionality at all, you can ignore these configurations items +## altogether. + +## viewvc_base_url: Base URL at which ViewVC may be accessed on this +## server. The default value for this option is determined at +## run-time by the various front-ends to the query script. +## +## Examples: +## viewvc_base_url = /viewvc.py +## viewvc_base_url = /viewvc.wsgi +## viewvc_base_url = /cgi-bin/viewvc +## viewvc_base_url = viewvc +## +## To disable cross-linking between the query script and ViewVC, +## uncomment this option and leave its value empty. +## +#viewvc_base_url = + +##--------------------------------------------------------------------------- diff -Nru viewvc-1.1.5/debian/changelog viewvc-1.1.23/debian/changelog --- viewvc-1.1.5/debian/changelog 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/changelog 2015-05-26 19:44:35.000000000 +0000 @@ -1,3 +1,55 @@ +viewvc (1.1.23-0ubuntu0~ppa1) trusty; urgency=medium + + * Update to latest 1.1.23 from upstream. + + -- Dominik Stadler (Ubuntu key) <dominik.stadler@gmx.at> Tue, 26 May 2015 21:44:02 +0200 + +viewvc (1.1.22-1) unstable; urgency=medium + + * New upstream release (closes: #614509). Main changes since last release + (1.1.5) are: + - Improved root look and SVN cache performance. + - New 'max_filesize_kbytes' and 'binary_mime_types' configuration options. + - Tarball generation improvements. + - File content handling improvements. + - Miscellaneous cvsdb improvements. + - Add Basic authentication support to standalone.py. + - The charset detection code is more robust. + - Remote SVN views are now more performant and robust. + - Added support for custom revision log markup rules. + - Use Pygments lexer-guessing functionality. + - Fixed a lot of bugs in corner cases. + * I'm not able to see any problems with TypeError, so closes: #706096. + Please reopen if it keeps happening. + * There was a problem in the migration code from viewcvs into viewvc, but by + now everyone is in viewvc 1.1, so I'm sad to say that this finally closes: + #409864, #410273, #410324. + * This release ships two new binaries in each package: a WSGI and a FCGI + additionally to the normal CGI program, to give you any possible option. + * debian/control: + - Removed ancient Replaces and Conflicts with versions 8-10 years old. + - Added Vcs-* fields. + - Bumped Standards-Version to 3.9.5. + - Rewritten Descriptions for both packages to reflect that now we ship 3 + binaries. + - Add Depends on python, dh-python. + * debian/patches: + - Removed numbers from patches, remnants from the dpatch era, and appended + .patch suffix. + - Added DEP-3 headers to all of them. + - Patches rev2369, rev2547, rev2551, compression-content-length, + CVE-2012-3356, CVE-2012-3357 and CVE-2012-4533: Merged upstream. + - Remaining patches are resynced against current tree. + - shebang_wsgi_scripts.patch: Added to get rid of lintian warnings. + * debian/rules: Rewritten from scratch with latest abstractions in mind, + trying to mimic the old behavior. + * debian/NEWS: Removed. + * debian/source/format: Moved to 3.0 (quilt). + * debian/compat: Bumped to 9, modified debian/control. + * debian/watch: Added. + + -- David Martínez Moreno <ender@debian.org> Thu, 10 Jul 2014 21:42:45 +0200 + viewvc (1.1.5-1.4) unstable; urgency=high * Non-maintainer upload. @@ -411,7 +463,7 @@ viewcvs (0.9.2+cvs.1.0.dev.2004.07.28-3) unstable; urgency=low - * Sigh. Really change maintainer in debian/control. Thanks, + * Sigh. Really change maintainer in debian/control. Thanks, Martin Michlmayr. -- David Martínez Moreno <ender@debian.org> Fri, 17 Jun 2005 06:25:14 +0200 diff -Nru viewvc-1.1.5/debian/compat viewvc-1.1.23/debian/compat --- viewvc-1.1.5/debian/compat 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/compat 2015-05-26 19:38:20.000000000 +0000 @@ -1 +1 @@ -7 +9 diff -Nru viewvc-1.1.5/debian/control viewvc-1.1.23/debian/control --- viewvc-1.1.5/debian/control 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/control 2015-05-26 19:38:20.000000000 +0000 @@ -2,17 +2,17 @@ Section: vcs Priority: optional Maintainer: David Martínez Moreno <ender@debian.org> -Build-Depends-Indep: python, python-subversion, python-support (>= 0.8) -Build-Depends: debhelper (>= 7), quilt -Standards-Version: 3.8.4 -XS-Python-Version: all +Build-Depends-Indep: python, python-subversion, dh-python +Build-Depends: debhelper (>= 9), quilt +Standards-Version: 3.9.5 +X-Python-Version: all Homepage: http://www.viewvc.org/ +Vcs-Git: git://anonscm.debian.org/collab-maint/viewvc.git +Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/viewvc.git;a=summary Package: viewvc Architecture: all -Depends: ${python:Depends}, python-subversion, cvs | subversion, rcs, ${misc:Depends} -Replaces: viewcvs (<< 0.9.4) -Conflicts: viewcvs (<< 0.9.4) +Depends: python, ${python:Depends}, python-subversion, cvs | subversion, rcs, ${misc:Depends} Recommends: python-pygments, apache2 | httpd-cgi Suggests: cvsgraph, viewvc-query, libapache2-mod-python, python-tk, mime-support XB-Python-Version: ${python:Versions} @@ -29,13 +29,14 @@ ViewVC can be used in two modes, both of which are supported by this package: (1) by running the simple stand-alone server "viewvc-standalone", with or without a GUI, and/or (2) by integrating - ViewVC with Apache (or another CGI-enabled HTTP server), using either - CGI or mod-python. This second mode is the normal way ViewVC is used. + ViewVC with any CGI-enabled HTTP server like Apache or nginx. + . + Three different binaries are provided: FastCGI, WSGI (for Apache mod_python), + and plain CGI. Package: viewvc-query Architecture: all -Depends: viewvc (= ${binary:Version}), python-mysqldb, ${python:Depends}, ${misc:Depends} -Replaces: viewvc (<< 0.9.2-6) +Depends: viewvc (= ${binary:Version}), python, python-mysqldb, ${python:Depends}, ${misc:Depends} Suggests: mysql-server XB-Python-Version: ${python:Versions} Description: utility to query CVS and Subversion commit database @@ -44,8 +45,8 @@ navigable directory, revision, and change log listings. It can display specific versions of files as well as diffs between those versions. . - This package includes query.cgi (and equivalent mod-python modules): a - utility to query a separate CVS and Subversion commit database. You can - search for multiple matches by typing comma-separated lists into the + This package includes query.cgi (and equivalent FastCGI and mod-python + variants): a utility to query a separate CVS and Subversion commit database. + You can search for multiple matches by typing comma-separated lists into the text fields. Regular expressions and wildcards are also supported. It requires a stand-alone MySQL database server. diff -Nru viewvc-1.1.5/debian/NEWS viewvc-1.1.23/debian/NEWS --- viewvc-1.1.5/debian/NEWS 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/NEWS 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -viewvc (1.1.5-1) unstable; urgency=medium - - * The ViewVC packages (viewvc, viewvc-query and viewcvs) have been - reorganised rather extensively. However, upgrading from an older - version _should_ result in a still-working installation. - - * The Apache mod-python modules are now part of the Debian packages; - these are installed to /usr/lib/viewvc/mod-python. See README.Debian - for information on how to use these modules. - - * All references to Debconf have been removed. Previous versions of - this package violated Debian policy (section 10.7.3): the file - /etc/viewvc/viewvc.conf is a conffile, and maintainer scripts must NOT - modify it at any time. The shipped viewvc.conf file does not have any - CVS or Subversion repositories defined. - - * The "*docroot*" path has been moved from /usr/share/viewvc to - /usr/share/viewvc/docroot. This new location better complies with the - Webapps Policy, section 3.1. - - -- John Zaitseff <J.Zaitseff@zap.org.au> Thu, 01 Apr 2010 13:08:05 +1100 diff -Nru viewvc-1.1.5/debian/patches/01-robots-support viewvc-1.1.23/debian/patches/01-robots-support --- viewvc-1.1.5/debian/patches/01-robots-support 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/01-robots-support 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Index: trunk/bin/cgi/viewvc.cgi -=================================================================== ---- trunk.orig/bin/cgi/viewvc.cgi 2010-03-31 11:48:35.000000000 +1100 -+++ trunk/bin/cgi/viewvc.cgi 2010-03-31 11:57:56.000000000 +1100 -@@ -47,6 +47,17 @@ - "../../../lib"))) - - ######################################################################### -+# -+# Disable robots -+# -+ -+PATH_INFO = os.environ.get('PATH_INFO', '') -+if PATH_INFO == '/robots.txt': -+ print "Content-Type: text/plain\n\nUser-agent: *\nDisallow: /\n" -+ sys.exit(0) -+ -+ -+######################################################################### - - ### add code for checking the load average - diff -Nru viewvc-1.1.5/debian/patches/90-viewvc-install-debian-paths viewvc-1.1.23/debian/patches/90-viewvc-install-debian-paths --- viewvc-1.1.5/debian/patches/90-viewvc-install-debian-paths 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/90-viewvc-install-debian-paths 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -Index: trunk/viewvc-install -=================================================================== ---- trunk.orig/viewvc-install 2010-03-31 19:36:34.000000000 +1100 -+++ trunk/viewvc-install 2010-03-31 20:00:56.000000000 +1100 -@@ -49,10 +49,10 @@ - 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/mod_python/viewvc.py", "bin/mod_python/viewvc.py", 0644, 1, 0, 0), -+ ("bin/mod_python/query.py", "bin/mod_python/query.py", 0644, 1, 0, 0), -+ ("bin/mod_python/handler.py", "bin/mod_python/handler.py", 0644, 1, 0, 0), -+ ("bin/mod_python/.htaccess", "bin/mod_python/.htaccess", 0644, 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), -@@ -122,7 +122,7 @@ - """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)) -+ repl = '%s = r"%s"' % (var, value) - return re.sub(pattern, _escape(repl), contents) - - -@@ -131,8 +131,8 @@ - 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') -+ contents = replace_var(contents, 'LIBRARY_DIR', '/usr/lib/viewvc/lib') -+ contents = replace_var(contents, 'CONF_PATHNAME', '/etc/viewvc/viewvc.conf') - return contents - - diff -Nru viewvc-1.1.5/debian/patches/91-viewvc-conf-debian-custom viewvc-1.1.23/debian/patches/91-viewvc-conf-debian-custom --- viewvc-1.1.5/debian/patches/91-viewvc-conf-debian-custom 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/91-viewvc-conf-debian-custom 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -Index: trunk/conf/viewvc.conf.dist -=================================================================== ---- trunk.orig/conf/viewvc.conf.dist 2010-04-01 09:34:36.000000000 +1100 -+++ trunk/conf/viewvc.conf.dist 2010-04-01 09:41:07.000000000 +1100 -@@ -93,7 +93,7 @@ - ## cvs_roots = cvsroot: /opt/cvs/repos1, - ## anotherroot: /usr/local/cvs/repos2 - ## --#cvs_roots = -+#cvs_roots = cvs: /var/lib/cvs - - ## svn_roots: Specifies each of the Subversion roots (repositories) on - ## your system and assigns names to them. Each root should be given by -@@ -104,7 +104,7 @@ - ## svn_roots = svnrepos: /opt/svn/, - ## anotherrepos: /usr/local/svn/repos2 - ## --#svn_roots = -+#svn_roots = svn: /var/lib/svn - - ## root_parents: Specifies a list of directories in which any number of - ## repositories may reside. Rather than force you to add a new entry -@@ -520,7 +520,7 @@ - ## SEE ALSO: the [templates] configuration section, where you can - ## override templates on a per-view basis. - ## --#template_dir = templates -+template_dir = /etc/viewvc/templates - - ## docroot: Web path to a directory that contains ViewVC static files - ## (stylesheets, images, etc.) If set, static files will get diff -Nru viewvc-1.1.5/debian/patches/92-no_strings_in_raise viewvc-1.1.23/debian/patches/92-no_strings_in_raise --- viewvc-1.1.5/debian/patches/92-no_strings_in_raise 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/92-no_strings_in_raise 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -Index: viewvc-1.1.5/lib/vclib/ccvs/ccvs.py -=================================================================== ---- viewvc-1.1.5.orig/lib/vclib/ccvs/ccvs.py -+++ viewvc-1.1.5/lib/vclib/ccvs/ccvs.py -@@ -302,7 +302,7 @@ class TreeSink(rcsparse.Sink): - added = added + count - idx = idx + count - elif command: -- raise "error while parsing deltatext: %s" % command -+ raise vclib.Error("error while parsing deltatext: %s" % command) - - if len(rev.number) == 2: - rev.next_changed = changed and "+%i -%i" % (deled, added) -Index: viewvc-1.1.5/lib/win32popen.py -=================================================================== ---- viewvc-1.1.5.orig/lib/win32popen.py -+++ viewvc-1.1.5/lib/win32popen.py -@@ -184,7 +184,7 @@ def SpoolWorker(srcHandle, destHandle, o - hr, data = win32file.ReadFile(srcHandle, buffer) - #print >> SPOOL_ERROR, "ReadFile returned '%s', '%s'" % (str(hr), str(data)); SPOOL_ERROR.flush() - if hr != 0: -- raise "win32file.ReadFile returned %i, '%s'" % (hr, data) -+ raise Exception("win32file.ReadFile returned %i, '%s'" % (hr, data)) - elif len(data) == 0: - break - except pywintypes.error, e: -@@ -205,7 +205,7 @@ def SpoolWorker(srcHandle, destHandle, o - hr, bytes = win32file.WriteFile(destHandle, data) - #print >> SPOOL_ERROR, "WriteFile() passed %i bytes and returned %i, %i" % (len(data), hr, bytes); SPOOL_ERROR.flush() - if hr != 0 or bytes != len(data): -- raise "win32file.WriteFile() passed %i bytes and returned %i, %i" % (len(data), hr, bytes) -+ raise Exception("win32file.WriteFile() passed %i bytes and returned %i, %i" % (len(data), hr, bytes)) - - srcHandle.Close() - diff -Nru viewvc-1.1.5/debian/patches/compression-content-length viewvc-1.1.23/debian/patches/compression-content-length --- viewvc-1.1.5/debian/patches/compression-content-length 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/compression-content-length 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -Description: Fix issue #467 (I think...) by not claiming a particular content - length when compression would skew that. - . - * lib/viewvc.py - (get_writeready_server_file): Add optional 'content_length' - parameter, and the code to handle it. - (view_doc): Update call to get_writeready_server_file(). -Origin: upstream, svn r2471 -Bug: http://viewvc.tigris.org/issues/show_bug.cgi?id=467 -Bug-Debian: http://bugs.debian.org/636805 -Author: C. Michael Pilato -Reviewed-by: gregor herrmann <gregoa@debian.org> -Last-Update: 2012-08-07 -Applied-Upstream: yup - ---- a/lib/viewvc.py -+++ b/lib/viewvc.py -@@ -896,13 +896,17 @@ - - return template - --def get_writeready_server_file(request, content_type=None): -+def get_writeready_server_file(request, content_type=None, content_length=None): - """Return a file handle to a response body stream, after outputting - any queued special headers (on REQUEST.server) and (optionally) a - 'Content-Type' header whose value is CONTENT_TYPE. After this is -- called, it is too late to add new headers to the response.""" -+ called, it is too late to add new headers to the response. -+ If CONTENT_LENGTH is provided and compression is not in use, also -+ generate a 'Content-Length' header for this response.""" - if request.gzip_compress_level: - request.server.addheader('Content-Encoding', 'gzip') -+ elif content_length is not None: -+ request.server.addheader('Content-Length', content_length) - if content_type: - request.server.header(content_type) - else: -@@ -2699,7 +2703,6 @@ - raise debug.ViewVCException('Static file "%s" not available (%s)' - % (document, str(v)), '404 Not Found') - -- request.server.addheader('Content-Length', content_length) - if document[-3:] == 'png': - mime_type = 'image/png' - elif document[-3:] == 'jpg': -@@ -2710,7 +2713,7 @@ - mime_type = 'text/css' - else: # assume HTML: - mime_type = None -- copy_stream(fp, get_writeready_server_file(request, mime_type)) -+ copy_stream(fp, get_writeready_server_file(request, mime_type, content_length)) - fp.close() - - def rcsdiff_date_reformat(date_str, cfg): diff -Nru viewvc-1.1.5/debian/patches/CVE-2012-3356 viewvc-1.1.23/debian/patches/CVE-2012-3356 --- viewvc-1.1.5/debian/patches/CVE-2012-3356 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/CVE-2012-3356 1970-01-01 00:00:00.000000000 +0000 @@ -1,368 +0,0 @@ -Bugs-Debian: http://bugs.debian.org/679069 -Description: fix CVE-2012-3356 -Last-Update: 2012-09-05 -Origin: upstream svn, cf. details below -Comment: this is the commit from upstream, with the path adjusted and quilt - refresh'd plus heavy manual backporting to the old version in Debian - because 5/13 hunks failed - -http://viewvc.tigris.org/source/browse/viewvc?view=rev&revision=2755 - -Author cmpilato -Date 2012-06-13 14:57:38-0700 (2 months, 3 weeks ago) -Log message - -For issue #353, check path access in the code that backs the revision -log view for remote SVN repositories. - -* lib/vclib/svn/svn_ra.py - (LogCollector.__init__): Add 'access_check_func' parameter, stashed - away as a member variable. Initialize 'done' variable to False. - (LogCollector.add_log): Use access_check_func() to test for access. - If access is denied, set 'done' to True and ignore future - invocations. - (RemoteSubversionRepository.itemlog): Add _access_checker inner - function, passed as a callback to LogCollector.__init__(). - -http://viewvc.tigris.org/source/browse/viewvc?view=rev&revision=2756 - -Author cmpilato -Date 2012-06-14 19:11:12-0700 (2 months, 3 weeks ago) -Log message - -For issue #353 ("Remote Subversion repositories not fully honoring -authz rules"): - -* lib/vclib/svn/svn_ra.py - (RemoteSubversionRepository.get_locations): Check authz on the - result of a get_locations lookup (being sure to use the original - path in the error message, if any). - -http://viewvc.tigris.org/source/browse/viewvc?view=rev&revision=2757 - -Author cmpilato -Date 2012-06-14 19:17:55-0700 (2 months, 3 weeks ago) -Log message - -For issue #353, check path access in the annotation view code for -remote SVN repositories. - -* lib/vclib/svn/svn_ra.py - (RemoteSubversionRepository.annotate): Examine revision logs to - determine the legal annotation range we are allowed to request, - and use the revinfo cache to strip sensitive author/data info from - the annotation data. - -http://viewvc.tigris.org/source/browse/viewvc?view=rev&revision=2759 - -Author cmpilato -Date 2012-06-15 16:07:22-0700 (2 months, 2 weeks ago) -Log message - -* lib/vclib/svn/svn_ra.py - (LogCollector.add_log): Allow the access_check_func to be None (and - avoid trying to call it in that case). - -http://viewvc.tigris.org/source/browse/viewvc?view=rev&revision=2760 - -Author cmpilato -Date 2012-06-15 16:34:01-0700 (2 months, 2 weeks ago) -Log message - -Finish, I believe, issue #353 ("Remote Subversion repositories not -fully honoring authz rules"). In doing so, this makes the svn_ra -module the most accurate it has ever been, hopefully without too -terribly much extra cost. - -* lib/vclib/svn/svn_ra.py - (RemoteSubversionRepository.listdir): No longer check access here. - That's handled down in _get_dirents() now. - (RemoteSubversionRepository.dirlogs): Don't check dirent access here. - Just ensure that the returned entries are those which are - represented in the (filtered) set return from _get_dirents(). - Also, replace the revision metadata stored on each dirent with - values from the revinfo cache (which does authz sanitizing). - (RemoteSubversionRepository._get_dirents): Do authz-checking of - dirents here, and use _get_last_history_rev() to populate a useful - created_rev. - (RemoteSubversionRepository._get_last_history_rev): Because - Subversion's RA layer doesn't consider copy events when - determining an item's last-committed-rev, compensate for this with - a bounded log operation which does. This brings created-rev - parity with the svn_repos module (at the cost of the extra RA - work, but with the benefit of, you know, accuracy. - (RemoteSubversionRepository._revinfo_raw): Leave a TODO about a - future optimization. - (RemoteSubversionRepository._log_cb): Set found_unreadable when - sanitizing an unreadable copyfrom path, too. - (RemoteSubversionRepository.created_rev): Now just a thin wrapper - around the beefed-up _get_last_history_rev() function. - -http://viewvc.tigris.org/source/browse/viewvc?view=rev&revision=2761 - -Author cmpilato -Date 2012-06-15 17:03:57-0700 (2 months, 2 weeks ago) -Log message - -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. - ---- a/lib/vclib/svn/svn_ra.py -+++ b/lib/vclib/svn/svn_ra.py -@@ -56,9 +56,8 @@ - - - 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 = '/' -@@ -67,8 +66,12 @@ - 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, paths, revision, author, date, message, pool): -+ if self.done: -+ return - # Changed paths have leading slashes - changed_paths = paths.keys() - changed_paths.sort(lambda a, b: _compare_paths(a, b)) -@@ -88,9 +91,13 @@ - 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, _datestr_to_date(date), author, message, 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, _datestr_to_date(date), author, message, None, -+ self.lockinfo, self.path[1:], None, None) -+ self.logs.append(entry) -+ else: -+ self.done = True - if this_path: - self.path = this_path - -@@ -229,7 +236,7 @@ - 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] -@@ -237,8 +244,9 @@ - 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): -@@ -249,9 +257,11 @@ - 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, changes = \ - self.revinfo(dirent.created_rev) - entry.rev = str(dirent.created_rev) -@@ -275,9 +285,14 @@ - if locks.has_key(basename): - lockinfo = locks[basename].owner - -+ 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 -@@ -290,6 +305,10 @@ - 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() -@@ -316,6 +335,14 @@ - rev = self._getrev(rev) - url = self._geturl(path) - -+ # Examine logs for the file to determine the oldest revision we are -+ # permitted to see. -+ revs = self.itemlog(path_parts, rev, vclib.SORTBY_REV, 0, 0, {}) -+ 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, -@@ -323,10 +350,14 @@ - prev_rev = None - if revision > 1: - prev_rev = revision - 1 -+ if revision >= 0: -+ date, author, msg, revprops, changes = self.revinfo(revision) -+ else: -+ date = author = None - blame_data.append(vclib.Annotation(line, line_no+1, revision, prev_rev, - author, None)) - -- client.svn_client_blame(url, _rev2optrev(1), _rev2optrev(rev), -+ client.svn_client_blame(url, _rev2optrev(oldest_rev), _rev2optrev(rev), - _blame_cb, self.ctx) - - return blame_data, rev -@@ -392,32 +423,73 @@ - - 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) - 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(path) + [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): -+ dirent.created_rev = self._get_last_history_rev(dirent_parts, 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 last interesting revision equal to or older than REV -+ in the history of PATH_PARTS.""" -+ -+ 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] -+ 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, 0, -+ lc.add_log, self.ctx) -+ revs = lc.logs -+ if revs: -+ revs.sort() -+ return revs[0].number -+ else: -+ return last_changed_rev - - def _revinfo_raw(self, rev): - # return 5-tuple (date, author, message, changes) -+ -+ ### TODO: This function and its related cache would benefit from -+ ### optimizations such as what the matching svn_repos functions -+ ### have, where the 'changes' information is only fully -+ ### calculated/authz-sanitized when the caller actually needs it. -+ - optrev = _rev2optrev(rev) - revs = [] - -@@ -457,10 +529,11 @@ - 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, 0, 0)) - found_readable = 1 -@@ -495,23 +568,15 @@ - 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)) -+ return self._get_last_history_rev(_path_parts(path), rev) - - def last_rev(self, path, peg_revision, limit_revision=None): - """Given PATH, known to exist in PEG_REVISION, find the youngest diff -Nru viewvc-1.1.5/debian/patches/CVE-2012-3357 viewvc-1.1.23/debian/patches/CVE-2012-3357 --- viewvc-1.1.5/debian/patches/CVE-2012-3357 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/CVE-2012-3357 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -Bugs-Debian: http://bugs.debian.org/679069 -Description: fix CVE-2012-3357 -Last-Update: 2012-09-05 -Origin: upstream svn, cf. details below -Comment: this is the original commit from upstream, with only the path - adjusted and quilt refresh'd - -http://viewvc.tigris.org/source/browse/viewvc?view=rev&revision=2758 - -Author cmpilato -Date 2012-06-15 16:05:47-0700 (2 months, 2 weeks ago) -Log message - -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. - -http://viewvc.tigris.org/source/browse/viewvc?view=rev&revision=2762 - -Author cmpilato -Date 2012-06-15 17:25:33-0700 (2 months, 2 weeks ago) -Log message - -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. - - ---- a/lib/vclib/svn/svn_repos.py -+++ b/lib/vclib/svn/svn_repos.py -@@ -648,6 +648,7 @@ - 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, diff -Nru viewvc-1.1.5/debian/patches/CVE-2012-4533 viewvc-1.1.23/debian/patches/CVE-2012-4533 --- viewvc-1.1.5/debian/patches/CVE-2012-4533 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/CVE-2012-4533 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Index: viewvc-1.1.5/lib/viewvc.py -=================================================================== ---- viewvc-1.1.5.orig/lib/viewvc.py 2012-10-20 17:50:09.000000000 -0300 -+++ viewvc-1.1.5/lib/viewvc.py 2012-10-20 17:51:24.000000000 -0300 -@@ -2819,7 +2819,7 @@ - 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 diff -Nru viewvc-1.1.5/debian/patches/no_strings_in_raise.patch viewvc-1.1.23/debian/patches/no_strings_in_raise.patch --- viewvc-1.1.5/debian/patches/no_strings_in_raise.patch 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/patches/no_strings_in_raise.patch 2015-05-26 19:46:29.000000000 +0000 @@ -0,0 +1,41 @@ +Description: Make exceptions valid again. + Modern Pythons don't allow a string in the raise command. +Author: David Martínez Moreno <ender@debian.org> +Forwarded: no +Last-Update: 2014-06-08 + +Index: git/lib/vclib/ccvs/ccvs.py +=================================================================== +--- git.orig/lib/vclib/ccvs/ccvs.py 2015-05-26 21:46:29.180520769 +0200 ++++ git/lib/vclib/ccvs/ccvs.py 2015-05-26 21:46:29.176520739 +0200 +@@ -314,7 +314,7 @@ + added = added + count + idx = idx + count + elif command: +- raise "error while parsing deltatext: %s" % command ++ raise vclib.Error("error while parsing deltatext: %s" % command) + + if len(rev.number) == 2: + rev.next_changed = changed and "+%i -%i" % (deled, added) +Index: git/lib/win32popen.py +=================================================================== +--- git.orig/lib/win32popen.py 2015-05-26 21:46:29.180520769 +0200 ++++ git/lib/win32popen.py 2015-05-26 21:46:29.176520739 +0200 +@@ -184,7 +184,7 @@ + hr, data = win32file.ReadFile(srcHandle, buffer) + #print >> SPOOL_ERROR, "ReadFile returned '%s', '%s'" % (str(hr), str(data)); SPOOL_ERROR.flush() + if hr != 0: +- raise "win32file.ReadFile returned %i, '%s'" % (hr, data) ++ raise Exception("win32file.ReadFile returned %i, '%s'" % (hr, data)) + elif len(data) == 0: + break + except pywintypes.error, e: +@@ -205,7 +205,7 @@ + hr, bytes = win32file.WriteFile(destHandle, data) + #print >> SPOOL_ERROR, "WriteFile() passed %i bytes and returned %i, %i" % (len(data), hr, bytes); SPOOL_ERROR.flush() + if hr != 0 or bytes != len(data): +- raise "win32file.WriteFile() passed %i bytes and returned %i, %i" % (len(data), hr, bytes) ++ raise Exception("win32file.WriteFile() passed %i bytes and returned %i, %i" % (len(data), hr, bytes)) + + srcHandle.Close() + diff -Nru viewvc-1.1.5/debian/patches/rev2369 viewvc-1.1.23/debian/patches/rev2369 --- viewvc-1.1.5/debian/patches/rev2369 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/rev2369 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ ---- a/lib/sapi.py -+++ b/lib/sapi.py -@@ -33,6 +33,7 @@ server = None - # that character as-is, and sometimes needs to embed escaped values - # into HTML attributes. - def escape(s): -+ s = str(s) - s = string.replace(s, '&', '&') - s = string.replace(s, '>', '>') - s = string.replace(s, '<', '<') diff -Nru viewvc-1.1.5/debian/patches/rev2547 viewvc-1.1.23/debian/patches/rev2547 --- viewvc-1.1.5/debian/patches/rev2547 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/rev2547 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ ------------------------------------------------------------------------- -r2547 | cmpilato | 2011-04-19 21:40:04 +0100 (Tue, 19 Apr 2011) | 30 lines - -Try to make some sense of the various CVSdb-related limitation -mechanisms, namely by removing the largely redundant "global" limit -and allowing the per-query row limit (which already exist, too) to do -its work. - -While here, remove a poorly conceived (but thankfully unhighlighted) -mechanism for overriding the administrative limit on database rows -which was accessible via URL CGI params. - -* lib/viewvc.py - (_legal_params): Remove 'limit' as a legal parameter. - (view_query): No longer allow an undocumented URL parameter to - override the admin-declared SQL row limit. That should have never - been allowed! - -* lib/cvsdb.py - (CheckinDatabase.__init__): Remove 'row_limit' parameter and - associated self._row_limit member. - (CheckinDatabase.CreateSQLQueryString): No longer fuss with - self._row_limit. Let the individual query carry the row limit. - (ConnectDatabase): Update call to CheckinDatabase(). - -* lib/query.py - (form_to_cvsdb_query): Now accept 'cfg' parameter, and set the - query's row limit from the configured defaults. - (run_query): Update call to form_to_cvsdb_query(). - -* docs/url-reference.html - Remove reference to the 'limit' parameter. - ------------------------------------------------------------------------- ---- viewvc-1.1.5.orig/docs/url-reference.html -+++ viewvc-1.1.5/docs/url-reference.html -@@ -1193,13 +1193,6 @@ - page</td> - </tr> - <tr> -- <td><code>limit=<var>LIMIT</var></code></td> -- <td>optional</td> -- <td>maximum number of file-revisions to process during a -- query. Default is value of <code>row_limit</code> configuration -- option</td> -- </tr> -- <tr> - <td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td> - <td>optional</td> - <td>maximum number of files to list per commit in query ---- viewvc-1.1.5.orig/lib/cvsdb.py -+++ viewvc-1.1.5/lib/cvsdb.py -@@ -38,13 +38,12 @@ - ## complient database interface - - class CheckinDatabase: -- def __init__(self, host, port, user, passwd, database, row_limit): -+ def __init__(self, host, port, user, passwd, database): - self._host = host - self._port = port - self._user = user - self._passwd = passwd - self._database = database -- self._row_limit = row_limit - self._version = None - - ## database lookup caches -@@ -444,13 +443,11 @@ - conditions = string.join(joinConds + condList, " AND ") - conditions = conditions and "WHERE %s" % conditions - -- ## limit the number of rows requested or we could really slam -- ## a server with a large database -+ ## apply the query's row limit, if any (so we avoid really -+ ## slamming a server with a large database) - limit = "" - if query.limit: - limit = "LIMIT %s" % (str(query.limit)) -- elif self._row_limit: -- limit = "LIMIT %s" % (str(self._row_limit)) - - sql = "SELECT %s.* FROM %s %s %s %s" \ - % (commits_table, tables, conditions, order_by, limit) -@@ -769,8 +766,8 @@ - self.data = data - self.match = match - --## CheckinDatabaseQueryData is a object which contains the search parameters --## for a query to the CheckinDatabase -+## CheckinDatabaseQuery is an object which contains the search -+## parameters for a query to the Checkin Database - class CheckinDatabaseQuery: - def __init__(self): - ## sorting -@@ -861,7 +858,7 @@ - user = cfg.cvsdb.user - passwd = cfg.cvsdb.passwd - db = CheckinDatabase(cfg.cvsdb.host, cfg.cvsdb.port, user, passwd, -- cfg.cvsdb.database_name, cfg.cvsdb.row_limit) -+ cfg.cvsdb.database_name) - db.Connect() - return db - ---- viewvc-1.1.5.orig/lib/viewvc.py -+++ viewvc-1.1.5/lib/viewvc.py -@@ -706,7 +706,6 @@ - 'mindate' : _re_validate_datetime, - 'maxdate' : _re_validate_datetime, - 'format' : _re_validate_alpha, -- 'limit' : _re_validate_number, - - # for redirect_pathrev - 'orig_path' : None, -@@ -3959,7 +3958,6 @@ - mindate = request.query_dict.get('mindate', '') - maxdate = request.query_dict.get('maxdate', '') - format = request.query_dict.get('format') -- limit = int(request.query_dict.get('limit', 0)) - limit_changes = int(request.query_dict.get('limit_changes', - cfg.options.limit_changes)) - -@@ -4029,16 +4027,17 @@ - query.SetFromDateObject(mindate) - if maxdate is not None: - query.SetToDateObject(maxdate) -- if limit: -- query.SetLimit(limit) -- elif format == 'rss': -+ -+ # Set the admin-defined (via configuration) row limits. This is to avoid -+ # slamming the database server with a monster query. -+ if format == 'rss': - query.SetLimit(cfg.cvsdb.rss_row_limit) -+ else: -+ query.SetLimit(cfg.cvsdb.row_limit) - - # run the query - db.RunQuery(query) - -- sql = request.server.escape(db.CreateSQLQueryString(query)) -- - # gather commits - commits = [] - plus_count = 0 -@@ -4120,7 +4119,7 @@ - - data = common_template_data(request) - data.merge(ezt.TemplateData({ -- 'sql': sql, -+ 'sql': request.server.escape(db.CreateSQLQueryString(query)), - 'english_query': english_query(request), - 'queryform_href': request.get_url(view_func=view_queryform, escape=1), - 'backout_href': backout_href, ---- viewvc-1.1.5.orig/lib/query.py -+++ viewvc-1.1.5/lib/query.py -@@ -217,8 +217,9 @@ - else: - return "exact" - --def form_to_cvsdb_query(form_data): -+def form_to_cvsdb_query(cfg, form_data): - query = cvsdb.CreateCheckinQuery() -+ query.SetLimit(cfg.cvsdb.row_limit) - - if form_data.repository: - for cmd, str in listparse_string(form_data.repository): -@@ -380,7 +381,7 @@ - return ob - - def run_query(server, cfg, form_data, viewvc_link): -- query = form_to_cvsdb_query(form_data) -+ query = form_to_cvsdb_query(cfg, form_data) - db = cvsdb.ConnectDatabaseReadOnly(cfg) - db.RunQuery(query) - diff -Nru viewvc-1.1.5/debian/patches/rev2551 viewvc-1.1.23/debian/patches/rev2551 --- viewvc-1.1.5/debian/patches/rev2551 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/rev2551 1970-01-01 00:00:00.000000000 +0000 @@ -1,308 +0,0 @@ ------------------------------------------------------------------------- -r2551 | cmpilato | 2011-04-20 15:50:40 +0100 (Wed, 20 Apr 2011) | 41 lines - -Fix (to the degree that I believe is reasonable at this time) issue -#433 ("queries return only partial results"). When a database query -is artificially limited by the 'row_limit' setting, inform the user -that the returned data is incomplete. - -* lib/cvsdb.py - (CheckinDatabase.CreateSQLQueryString): Add 'detect_leftover' - parameter, used internally to check for a reached query limit. - (CheckinDatabase.RunQuery): Update call to CreateSQLQueryString(), - and check for leftover query response rows. If any are found, set - the appropriate flag on the query object. - (CheckinDatabaseQuery.__init__): Set initial values for new - 'executed' and 'limit_reached' members. - (CheckinDatabaseQuery.SetExecuted, - CheckinDatabaseQuery.SetLimitReached, - CheckinDatabaseQuery.GetLimitReached, - CheckinDatabaseQuery.GetCommitList): New functions. - -* lib/viewvc.py - (view_query): Use query.GetCommitList() now instead of poking into - the query object directly. Also, check query.GetLimitReached(), - reporting the findings through the data dictionary (via a new - 'row_limit_reached' item) to the templates. - -* lib/query.py - (run_query): Use query.GetCommitList() now instead of poking into - the query object directly. Now return a 2-tuple of commits and a - limit-reached flag. - (main): Update expectations of run_query() call. Populate - 'row_limit_reached' data dictionary item. - -* templates/query_results.ezt, -* templates/query.ezt - Display a warning if the query results are incomplete. - -* templates/docroot/styles.css - (.vc_warning): New style definition. - -* docs/template-authoring-guide.html - Document the new 'row_limit_reached' template item. - ------------------------------------------------------------------------- ---- viewvc-1.1.5.orig/docs/template-authoring-guide.html -+++ viewvc-1.1.5/docs/template-authoring-guide.html -@@ -1822,6 +1822,14 @@ - <tt>date</tt>, <tt>author</tt>, and <tt>file</tt>.</td> - </tr> - <tr class="varlevel1"> -+ <td class="varname">row_limit_reached</td> -+ <td>Boolean</td> -+ <td>Indicates whether the internal database row limit threshold (set -+ via the <code>cvsdb.row_limit</code> -+ and <code>cvsdb.rss_row_limit</code> configuration options) was -+ reached by the query.</td> -+</tr> -+<tr class="varlevel1"> - <td class="varname">show_branch</td> - <td>Boolean</td> - <td>Indicates whether or not to list branch names in the results. True ---- viewvc-1.1.5.orig/templates/query_results.ezt -+++ viewvc-1.1.5/templates/query_results.ezt -@@ -7,6 +7,15 @@ - - <p><strong>[english_query]</strong></p> - [# <!-- {sql} --> ] -+[if-any row_limit_reached] -+<p class="vc_warning">WARNING: These query results have been -+ artificially limited by an administrative threshold value and do -+ <em>not</em> represent the entirety of the data set which matches -+ the query. Consider <a href="[queryform_href]">modifying your -+ query to be more specific</a>, using your version control tool's -+ query capabilities, or asking your adminstrator to raise the -+ database response size threshold.</p> -+[end] - <p><a href="[queryform_href]">Modify query</a></p> - <p><a href="[backout_href]">Show commands which could be used to back out these changes</a></p> - ---- viewvc-1.1.5.orig/templates/query.ezt -+++ viewvc-1.1.5/templates/query.ezt -@@ -158,7 +158,15 @@ - [is query "skipped"] - [else] - <p><strong>[num_commits]</strong> matches found.</p> -- -+[if-any row_limit_reached] -+<p class="vc_warning">WARNING: These query results have been -+ artificially limited by an administrative threshold value and do -+ <em>not</em> represent the entirety of the data set which matches -+ the query. Consider modifying your query to be more specific</a>, -+ using your version control tool's query capabilities, or asking -+ your adminstrator to raise the database response size -+ threshold.</p> -+[end] - [if-any commits] - <table cellspacing="0" cellpadding="2"> - <thead> ---- viewvc-1.1.5.orig/templates/docroot/styles.css -+++ viewvc-1.1.5/templates/docroot/styles.css -@@ -272,3 +272,14 @@ - .vc_query_form { - background-color: #e6e6e6; - } -+ -+ -+/*** Warning! ***/ -+.vc_warning { -+ border-width: 1px 2px 2px 2px; -+ border-color: black; -+ border-style: solid; -+ background-color: red; -+ color: white; -+ padding: 0.5em; -+} ---- viewvc-1.1.5.orig/lib/cvsdb.py -+++ viewvc-1.1.5/lib/cvsdb.py -@@ -362,7 +362,7 @@ - - return "(%s)" % (string.join(sqlList, " OR ")) - -- def CreateSQLQueryString(self, query): -+ def CreateSQLQueryString(self, query, detect_leftover=0): - commits_table = self._version >= 1 and 'commits' or 'checkins' - tableList = [(commits_table, None)] - condList = [] -@@ -447,7 +447,10 @@ - ## slamming a server with a large database) - limit = "" - if query.limit: -- limit = "LIMIT %s" % (str(query.limit)) -+ if detect_leftover: -+ limit = "LIMIT %s" % (str(query.limit + 1)) -+ else: -+ limit = "LIMIT %s" % (str(query.limit)) - - sql = "SELECT %s.* FROM %s %s %s %s" \ - % (commits_table, tables, conditions, order_by, limit) -@@ -455,14 +458,20 @@ - return sql - - def RunQuery(self, query): -- sql = self.CreateSQLQueryString(query) -+ sql = self.CreateSQLQueryString(query, 1) - cursor = self.db.cursor() - cursor.execute(sql) -+ query.SetExecuted() -+ row_count = 0 - - while 1: - row = cursor.fetchone() - if not row: - break -+ row_count = row_count + 1 -+ if query.limit and (row_count > query.limit): -+ query.SetLimitReached() -+ break - - (dbType, dbCI_When, dbAuthorID, dbRepositoryID, dbDirID, - dbFileID, dbRevision, dbStickyTag, dbBranchID, dbAddedLines, -@@ -767,7 +776,8 @@ - self.match = match - - ## CheckinDatabaseQuery is an object which contains the search --## parameters for a query to the Checkin Database -+## parameters for a query to the Checkin Database and -- after the -+## query is executed -- the data returned by the query. - class CheckinDatabaseQuery: - def __init__(self): - ## sorting -@@ -787,7 +797,8 @@ - - ## limit on number of rows to return - self.limit = None -- -+ self.limit_reached = 0 -+ - ## list of commits -- filled in by CVS query - self.commit_list = [] - -@@ -795,6 +806,9 @@ - ## are added - self.commit_cb = None - -+ ## has this query been run? -+ self.executed = 0 -+ - def SetRepository(self, repository, match = "exact"): - self.repository_list.append(QueryEntry(repository, match)) - -@@ -840,6 +854,20 @@ - def AddCommit(self, commit): - self.commit_list.append(commit) - -+ def SetExecuted(self): -+ self.executed = 1 -+ -+ def SetLimitReached(self): -+ self.limit_reached = 1 -+ -+ def GetLimitReached(self): -+ assert self.executed -+ return self.limit_reached -+ -+ def GetCommitList(self): -+ assert self.executed -+ return self.commit_list -+ - - ## - ## entrypoints ---- viewvc-1.1.5.orig/lib/viewvc.py -+++ viewvc-1.1.5/lib/viewvc.py -@@ -4037,20 +4037,22 @@ - - # run the query - db.RunQuery(query) -- -+ commit_list = query.GetCommitList() -+ row_limit_reached = query.GetLimitReached() -+ - # gather commits - commits = [] - plus_count = 0 - minus_count = 0 - mod_time = -1 -- if query.commit_list: -+ if commit_list: - files = [] - limited_files = 0 -- current_desc = query.commit_list[0].GetDescriptionID() -- current_rev = query.commit_list[0].GetRevision() -+ current_desc = commit_list[0].GetDescriptionID() -+ current_rev = commit_list[0].GetRevision() - dir_strip = _path_join(repos_dir) - -- for commit in query.commit_list: -+ for commit in commit_list: - commit_desc = commit.GetDescriptionID() - commit_rev = commit.GetRevision() - -@@ -4128,6 +4130,7 @@ - 'show_branch': show_branch, - 'querysort': querysort, - 'commits': commits, -+ 'row_limit_reached' : ezt.boolean(row_limit_reached), - 'limit_changes': limit_changes, - 'limit_changes_href': limit_changes_href, - 'rss_link_href': request.get_url(view_func=view_query, ---- viewvc-1.1.5.orig/lib/query.py -+++ viewvc-1.1.5/lib/query.py -@@ -385,8 +385,11 @@ - db = cvsdb.ConnectDatabaseReadOnly(cfg) - db.RunQuery(query) - -- if not query.commit_list: -- return [ ] -+ commit_list = query.GetCommitList() -+ if not commit_list: -+ return [ ], 0 -+ -+ row_limit_reached = query.GetLimitReached() - - commits = [ ] - files = [ ] -@@ -397,8 +400,8 @@ - for key, value in rootitems: - cvsroots[cvsdb.CleanRepository(value)] = key - -- current_desc = query.commit_list[0].GetDescription() -- for commit in query.commit_list: -+ current_desc = commit_list[0].GetDescription() -+ for commit in commit_list: - desc = commit.GetDescription() - if current_desc == desc: - files.append(commit) -@@ -421,7 +424,7 @@ - return len(commit.files) > 0 - commits = filter(_only_with_files, commits) - -- return commits -+ return commits, row_limit_reached - - def main(server, cfg, viewvc_link): - try: -@@ -430,10 +433,12 @@ - form_data = FormData(form) - - if form_data.valid: -- commits = run_query(server, cfg, form_data, viewvc_link) -+ commits, row_limit_reached = run_query(server, cfg, -+ form_data, viewvc_link) - query = None - else: - commits = [ ] -+ row_limit_reached = 0 - query = 'skipped' - - data = ezt.TemplateData({ -@@ -453,6 +458,7 @@ - 'date' : form_data.date, - - 'query' : query, -+ 'row_limit_reached' : ezt.boolean(row_limit_reached), - 'commits' : commits, - 'num_commits' : len(commits), - 'rss_href' : None, diff -Nru viewvc-1.1.5/debian/patches/robots-support.patch viewvc-1.1.23/debian/patches/robots-support.patch --- viewvc-1.1.5/debian/patches/robots-support.patch 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/patches/robots-support.patch 2015-05-26 19:46:27.000000000 +0000 @@ -0,0 +1,31 @@ +Description: Prevent robots from hitting the ViewVC instance. + If ViewVC is in control of the /robots.txt URL, it will stop crawlers from + hitting every part of the repo, to avoid useless load. +Author: Kai Hendry <hendry@cs.helsinki.fi> +Bug-Debian: http://bugs.debian.org/196975 +Forwarded: no +Reviewed-By: David Martínez Moreno +Last-Update: 2014-06-08 + +Index: git/bin/cgi/viewvc.cgi +=================================================================== +--- git.orig/bin/cgi/viewvc.cgi 2015-05-26 21:46:27.468510038 +0200 ++++ git/bin/cgi/viewvc.cgi 2015-05-26 21:46:27.464510010 +0200 +@@ -47,6 +47,17 @@ + "../../../lib"))) + + ######################################################################### ++# ++# Disable robots ++# ++ ++PATH_INFO = os.environ.get('PATH_INFO', '') ++if PATH_INFO == '/robots.txt': ++ print "Content-Type: text/plain\n\nUser-agent: *\nDisallow: /\n" ++ sys.exit(0) ++ ++ ++######################################################################### + + ### add code for checking the load average + diff -Nru viewvc-1.1.5/debian/patches/series viewvc-1.1.23/debian/patches/series --- viewvc-1.1.5/debian/patches/series 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/patches/series 2015-05-26 19:38:20.000000000 +0000 @@ -1,11 +1,5 @@ -01-robots-support -90-viewvc-install-debian-paths -91-viewvc-conf-debian-custom -92-no_strings_in_raise -rev2369 -rev2547 -rev2551 -compression-content-length -CVE-2012-3357 -CVE-2012-3356 -CVE-2012-4533 +robots-support.patch +viewvc-install-debian-paths.patch +viewvc.conf-debian-custom.patch +no_strings_in_raise.patch +shebang_wsgi_scripts.patch diff -Nru viewvc-1.1.5/debian/patches/shebang_wsgi_scripts.patch viewvc-1.1.23/debian/patches/shebang_wsgi_scripts.patch --- viewvc-1.1.5/debian/patches/shebang_wsgi_scripts.patch 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/patches/shebang_wsgi_scripts.patch 2015-05-26 19:46:29.000000000 +0000 @@ -0,0 +1,24 @@ +Description: <short summary of the patch>dd shebangs for WSGI scripts. + Lintian is reporting executables without a shebang line, so adding it. +Author: David Martínez Moreno <ender@debian.org> +Forwarded: no +Last-Update: 2014-06-08 + +Index: git/bin/wsgi/query.wsgi +=================================================================== +--- git.orig/bin/wsgi/query.wsgi 2015-05-26 21:46:29.572523220 +0200 ++++ git/bin/wsgi/query.wsgi 2015-05-26 21:46:29.572523220 +0200 +@@ -1,3 +1,4 @@ ++#!/usr/bin/python + # -*-python-*- + # + # Copyright (C) 1999-2014 The ViewCVS Group. All Rights Reserved. +Index: git/bin/wsgi/viewvc.wsgi +=================================================================== +--- git.orig/bin/wsgi/viewvc.wsgi 2015-05-26 21:46:29.572523220 +0200 ++++ git/bin/wsgi/viewvc.wsgi 2015-05-26 21:46:29.572523220 +0200 +@@ -1,3 +1,4 @@ ++#!/usr/bin/python + # -*-python-*- + # + # Copyright (C) 1999-2014 The ViewCVS Group. All Rights Reserved. diff -Nru viewvc-1.1.5/debian/patches/viewvc.conf-debian-custom.patch viewvc-1.1.23/debian/patches/viewvc.conf-debian-custom.patch --- viewvc-1.1.5/debian/patches/viewvc.conf-debian-custom.patch 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/patches/viewvc.conf-debian-custom.patch 2015-05-26 19:46:28.000000000 +0000 @@ -0,0 +1,38 @@ +Description: Create good defaults for viewvc.conf. + Make default values for the CVS and SVN repos directories, and the + templates directory. +Author: David Martínez Moreno <ender@debian.org> +Forwarded: no +Last-Update: 2014-06-08 + +Index: git/conf/viewvc.conf.dist +=================================================================== +--- git.orig/conf/viewvc.conf.dist 2015-05-26 21:46:28.724517911 +0200 ++++ git/conf/viewvc.conf.dist 2015-05-26 21:46:28.720517882 +0200 +@@ -93,7 +93,7 @@ + ## cvs_roots = cvsroot: /opt/cvs/repos1, + ## anotherroot: /usr/local/cvs/repos2 + ## +-#cvs_roots = ++#cvs_roots = cvs: /var/lib/cvs + + ## svn_roots: Specifies each of the Subversion roots (repositories) on + ## your system and assigns names to them. Each root should be given by +@@ -109,7 +109,7 @@ + ## svn_roots = svnrepos: /opt/svn/, + ## anotherrepos: /usr/local/svn/repos2 + ## +-#svn_roots = ++#svn_roots = svn: /var/lib/svn + + ## root_parents: Specifies a list of directories under which any + ## number of repositories may reside. You can specify multiple root +@@ -629,7 +629,7 @@ + ## SEE ALSO: the [templates] configuration section, where you can + ## override templates on a per-view basis. + ## +-#template_dir = templates ++template_dir = /etc/viewvc/templates + + ## docroot: Web path to a directory that contains ViewVC static files + ## (stylesheets, images, etc.) If set, static files will get diff -Nru viewvc-1.1.5/debian/patches/viewvc-install-debian-paths.patch viewvc-1.1.23/debian/patches/viewvc-install-debian-paths.patch --- viewvc-1.1.5/debian/patches/viewvc-install-debian-paths.patch 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/patches/viewvc-install-debian-paths.patch 2015-05-26 19:46:28.000000000 +0000 @@ -0,0 +1,45 @@ +Description: Proper path and permissions for several installed files. + Debianize and fix permissions in the install script. +Author: David Martínez Moreno <ender@debian.org> +Forwarded: no +Last-Update: 2014-06-08 + +Index: git/viewvc-install +=================================================================== +--- git.orig/viewvc-install 2015-05-26 21:46:28.220514750 +0200 ++++ git/viewvc-install 2015-05-26 21:46:28.216514722 +0200 +@@ -53,10 +53,10 @@ + ("bin/wsgi/viewvc.fcgi", "bin/wsgi/viewvc.fcgi", 0755, 1, 0, 0), + ("bin/wsgi/query.wsgi", "bin/wsgi/query.wsgi", 0755, 1, 0, 0), + ("bin/wsgi/query.fcgi", "bin/wsgi/query.fcgi", 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/mod_python/viewvc.py", "bin/mod_python/viewvc.py", 0644, 1, 0, 0), ++ ("bin/mod_python/query.py", "bin/mod_python/query.py", 0644, 1, 0, 0), ++ ("bin/mod_python/handler.py", "bin/mod_python/handler.py", 0644, 1, 0, 0), ++ ("bin/mod_python/.htaccess", "bin/mod_python/.htaccess", 0644, 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), +@@ -126,7 +126,7 @@ + """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)) ++ repl = '%s = r"%s"' % (var, value) + return re.sub(pattern, _escape(repl), contents) + + +@@ -135,8 +135,8 @@ + 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') ++ contents = replace_var(contents, 'LIBRARY_DIR', '/usr/lib/viewvc/lib') ++ contents = replace_var(contents, 'CONF_PATHNAME', '/etc/viewvc/viewvc.conf') + return contents + + diff -Nru viewvc-1.1.5/debian/rules viewvc-1.1.23/debian/rules --- viewvc-1.1.5/debian/rules 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/rules 2015-05-26 19:38:20.000000000 +0000 @@ -1,65 +1,26 @@ #!/usr/bin/make -f # debian/rules: Create the Debian packages for the ViewVC project -# Copyright (C) 2006-10, David Martínez Moreno and John Zaitseff +# Copyright (C) 2014, David Martínez Moreno. +# # Licensed under GPLv2. # Uncomment the following line for verbose Debhelper mode #export DH_VERBOSE=1 -STAMP_PATCH ?= debian/stamp-patch -STAMP_BUILD ?= debian/stamp-build +%: + dh $@ --with python2 - -default: binary - - -# Include the quilt targets "patch" and "unpatch" -include /usr/share/quilt/quilt.make - - -build: $(STAMP_BUILD) -$(STAMP_BUILD): patch - dh_testdir - touch $(STAMP_BUILD) - -clean: unpatch - dh_testdir - dh_testroot - find lib -name '*.pyc' -exec rm {} \; - rm -f $(STAMP_BUILD) +override_dh_clean: + find lib -name '*.pyc' -delete dh_clean -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs +override_dh_install: ./viewvc-install --prefix=/usr/lib/viewvc --destdir=debian/tmp - find debian/tmp -name '*.pyc' -exec rm {} \; - rm -fr debian/tmp/usr/lib/viewvc/lib/vclib/ccvs/rcsparse/test-data - mv debian/tmp/usr/lib/viewvc/templates/docroot debian/viewvc/usr/share/viewvc/docroot - dh_install --sourcedir=debian/tmp --list-missing - -binary: binary-arch binary-indep -binary-arch: build install -binary-indep: build install - dh_testdir - dh_testroot - dh_installchangelogs -pviewvc CHANGES - dh_installdocs -pviewvc INSTALL docs - dh_installexamples - dh_installman -pviewvc debian/viewvc-standalone.1 - dh_pysupport - dh_link - dh_strip - dh_compress -X/templates-contrib/ - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb + dh_install --fail-missing -Xvclib/ccvs/rcsparse/test-data +override_dh_installdocs: + dh_installdocs --link-doc=viewvc -.PHONY: default build clean install binary binary-arch binary-indep +override_dh_compress: + dh_compress -X/templates-contrib/ diff -Nru viewvc-1.1.5/debian/source/format viewvc-1.1.23/debian/source/format --- viewvc-1.1.5/debian/source/format 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/source/format 2015-05-26 19:38:20.000000000 +0000 @@ -0,0 +1 @@ +3.0 (quilt) diff -Nru viewvc-1.1.5/debian/viewvc.docs viewvc-1.1.23/debian/viewvc.docs --- viewvc-1.1.5/debian/viewvc.docs 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/viewvc.docs 2015-05-26 19:38:20.000000000 +0000 @@ -0,0 +1,2 @@ +INSTALL +docs diff -Nru viewvc-1.1.5/debian/viewvc.install viewvc-1.1.23/debian/viewvc.install --- viewvc-1.1.5/debian/viewvc.install 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/viewvc.install 2015-05-26 19:38:20.000000000 +0000 @@ -1,10 +1,13 @@ -usr/lib/viewvc/*.conf /etc/viewvc -usr/lib/viewvc/*.conf.dist /usr/share/doc/viewvc/examples +usr/lib/viewvc/*.conf /etc/viewvc +usr/lib/viewvc/*.conf.dist /usr/share/doc/viewvc/examples usr/lib/viewvc/bin/standalone.py /usr/lib/viewvc/bin usr/lib/viewvc/bin/cgi/viewvc.cgi /usr/lib/viewvc/cgi-bin +usr/lib/viewvc/bin/wsgi/viewvc.*gi /usr/lib/viewvc/cgi-bin usr/lib/viewvc/bin/mod_python/.htaccess /usr/lib/viewvc/mod-python usr/lib/viewvc/bin/mod_python/handler.py /usr/lib/viewvc/mod-python usr/lib/viewvc/bin/mod_python/viewvc.py /usr/lib/viewvc/mod-python -usr/lib/viewvc/lib/ /usr/lib/viewvc -usr/lib/viewvc/templates/ /etc/viewvc +usr/lib/viewvc/lib/ /usr/lib/viewvc +usr/lib/viewvc/templates/*.ezt /etc/viewvc/templates +usr/lib/viewvc/templates/include/ /etc/viewvc/templates +usr/lib/viewvc/templates/docroot/ /usr/share/viewvc usr/lib/viewvc/templates-contrib/ /usr/share/doc/viewvc/examples diff -Nru viewvc-1.1.5/debian/viewvc.links viewvc-1.1.23/debian/viewvc.links --- viewvc-1.1.5/debian/viewvc.links 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/viewvc.links 2015-05-26 19:38:20.000000000 +0000 @@ -1,3 +1,5 @@ /usr/lib/viewvc/bin/standalone.py /usr/bin/viewvc-standalone /usr/lib/viewvc/cgi-bin/viewvc.cgi /usr/lib/cgi-bin/viewvc.cgi +/usr/lib/viewvc/cgi-bin/viewvc.fcgi /usr/lib/cgi-bin/viewvc.fcgi +/usr/lib/viewvc/cgi-bin/viewvc.wsgi /usr/lib/cgi-bin/viewvc.wsgi /usr/share/viewvc/docroot /etc/viewvc/templates/docroot diff -Nru viewvc-1.1.5/debian/viewvc.manpages viewvc-1.1.23/debian/viewvc.manpages --- viewvc-1.1.5/debian/viewvc.manpages 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/viewvc.manpages 2015-05-26 19:38:20.000000000 +0000 @@ -0,0 +1 @@ +debian/viewvc-standalone.1 diff -Nru viewvc-1.1.5/debian/viewvc-query.install viewvc-1.1.23/debian/viewvc-query.install --- viewvc-1.1.5/debian/viewvc-query.install 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/viewvc-query.install 2015-05-26 19:38:20.000000000 +0000 @@ -3,4 +3,5 @@ usr/lib/viewvc/bin/make-database /usr/lib/viewvc/bin usr/lib/viewvc/bin/svndbadmin /usr/lib/viewvc/bin usr/lib/viewvc/bin/cgi/query.cgi /usr/lib/viewvc/cgi-bin +usr/lib/viewvc/bin/wsgi/query.*gi /usr/lib/viewvc/cgi-bin usr/lib/viewvc/bin/mod_python/query.py /usr/lib/viewvc/mod-python diff -Nru viewvc-1.1.5/debian/viewvc-query.links viewvc-1.1.23/debian/viewvc-query.links --- viewvc-1.1.5/debian/viewvc-query.links 2015-05-26 19:49:15.000000000 +0000 +++ viewvc-1.1.23/debian/viewvc-query.links 2015-05-26 19:38:20.000000000 +0000 @@ -3,4 +3,5 @@ /usr/lib/viewvc/bin/make-database /usr/sbin/viewvc-make-database /usr/lib/viewvc/bin/svndbadmin /usr/sbin/viewvc-svndbadmin /usr/lib/viewvc/cgi-bin/query.cgi /usr/lib/cgi-bin/query.cgi -/usr/share/doc/viewvc /usr/share/doc/viewvc-query +/usr/lib/viewvc/cgi-bin/query.fcgi /usr/lib/cgi-bin/query.fcgi +/usr/lib/viewvc/cgi-bin/query.wsgi /usr/lib/cgi-bin/query.wsgi diff -Nru viewvc-1.1.5/debian/watch viewvc-1.1.23/debian/watch --- viewvc-1.1.5/debian/watch 1970-01-01 00:00:00.000000000 +0000 +++ viewvc-1.1.23/debian/watch 2015-05-26 19:38:20.000000000 +0000 @@ -0,0 +1,5 @@ +# Compulsory line, this is a version 3 file +version=3 + +# <Webpage URL> <string match> +http://viewvc.tigris.org/servlets/ProjectDocumentList?folderID=6004 /files/documents/.*/viewvc-(.*)\.tar\.gz diff -Nru viewvc-1.1.5/docs/template-authoring-guide.html viewvc-1.1.23/docs/template-authoring-guide.html --- viewvc-1.1.5/docs/template-authoring-guide.html 2009-10-25 20:57:16.000000000 +0000 +++ viewvc-1.1.23/docs/template-authoring-guide.html 2011-11-03 14:22:25.000000000 +0000 @@ -1,6 +1,6 @@ <html> <head> -<title>ViewVC 1.0 Template Authoring Guide +ViewVC 1.1 Template Authoring Guide