# # # rename "template.py" # to "html.py" # # patch "TODO" # from [3b9eeae8ebfbf95f7a2c47507f315c2c88255d90] # to [399f28ec8945b71e5922e2e5755a39ca76186185] # # patch "fileinbranch.psp" # from [b5303538fa3fc8a567d758d257de52f79004414f] # to [1a5ec0aa9530386210ccb93413817ff2772bad69] # # patch "headofbranch.psp" # from [5949f4c3976c2860d25028f005f6f5e19a4995d3] # to [10181f7970817021dd721e9da72d9b06cc8ee9a1] # # patch "help.psp" # from [d843b4cf91401b2e616177f8536d6d43c831fb7d] # to [69f5d6ad53fe27808ef2841c2839816ba8f175ec] # # patch "html.py" # from [58338ce2547a9bc13e33f7ce670331c8cf9e91e5] # to [918ee71ec6f5ccb116ed425671dd1cad616c9079] # # patch "index.psp" # from [91b20f95e6c81b15fa20307e27ab590700ea8200] # to [7e7615f64309e31945a470f377f0acdf5e8ae832] # # patch "monotone.py" # from [bae49e4c0a167cf50c06a029d3f384d862d36741] # to [ecef0d77b01add91f83b6cf4a04d60e9f1da7217] # # patch "revision.psp" # from [51027eadc7443245e40030623274abe7202eef2b] # to [6f463be44003bf7015196427c19b940a52be7cb1] # # patch "tags.psp" # from [ebf8689665678fbcb9a90537d5f1fae8c2da73b8] # to [df24079a00706530ae62c60e9224dddaf048b25c] # # patch "tarofbranch.psp" # from [a213fcbd0ade73bb588d5d4b37bc9174b24299a4] # to [7559dc9f90f183396c4dff99903f5ea1f12e01cc] # # patch "wrapper.py" # from [7444ff00e621412e16056b61cc1e9663219b417b] # to [c5ff5ec5ea7868257307f1cf0731868986d38772] # ============================================================ --- TODO 3b9eeae8ebfbf95f7a2c47507f315c2c88255d90 +++ TODO 399f28ec8945b71e5922e2e5755a39ca76186185 @@ -5,6 +5,8 @@ a link to each ancestor in which the file is different from the revision we are displaying + * getfile.py is setting the wrong content-disposition header + TODO: * monotone automate stdio client @@ -31,3 +33,9 @@ * Improve the manifest; icons next to files indicating type (steal the icons from GNOME?) + * Show the version of viewmtn (rev + release) on each page, so that + it's easier to figure out what people are running when helping them + with problems. + + * Colour the diffs, colour files. + ============================================================ --- fileinbranch.psp b5303538fa3fc8a567d758d257de52f79004414f +++ fileinbranch.psp 1a5ec0aa9530386210ccb93413817ff2772bad69 @@ -1,12 +1,9 @@ <% import config import monotone import common import urllib -import template -from template import header,footer -from monotone import Monotone from common import link psp.set_error_page("error.psp") @@ -24,8 +21,6 @@ # in a branch (and present a choice iff there # are multiple heads and the files difer in them) -mt = Monotone(config.monotone, config.dbfile) - heads = mt.heads(branch) if len(heads) == 0: raise Exception("No head ID can be determined for this branch.") @@ -57,7 +52,7 @@ else: hq = common.html_escape() info = {'title' : "Latest version of %s in branch %s" % (hq(path), hq(branch))} - req.write(header(info)) + req.write(template.header(info)) %>

The branch you have selected has multiple head revisions, and the file you are attempting ============================================================ --- headofbranch.psp 5949f4c3976c2860d25028f005f6f5e19a4995d3 +++ headofbranch.psp 10181f7970817021dd721e9da72d9b06cc8ee9a1 @@ -1,12 +1,9 @@ <% import config import monotone import common import urllib -import template -from template import header,footer -from monotone import Monotone from common import link psp.set_error_page("error.psp") @@ -25,8 +22,6 @@ # otherwise, redirect to revision.psp and show that # ID. -mt = Monotone(config.monotone, config.dbfile) - heads = mt.heads(branch) if len(heads) == 0: raise Exception("No head ID can be determined for this branch.") @@ -37,7 +32,7 @@ else: hq = common.html_escape() info = {'title' : "Branch details for %s" % (hq(branch))} - req.write(header(info)) + req.write(template.header(info)) %>

The following head IDs are available. Please select one to view. ============================================================ --- help.psp d843b4cf91401b2e616177f8536d6d43c831fb7d +++ help.psp 69f5d6ad53fe27808ef2841c2839816ba8f175ec @@ -1,14 +1,12 @@ <% import config import common import urllib -import template -from template import header,footer psp.set_error_page("error.psp") info = { 'title' : "Help" } -req.write(header(info)) +req.write(template.header(info)) hq = common.html_escape() %> ============================================================ --- template.py 58338ce2547a9bc13e33f7ce670331c8cf9e91e5 +++ html.py 918ee71ec6f5ccb116ed425671dd1cad616c9079 @@ -1,28 +1,29 @@ import time +from viewmtn import release -def header(info): - if not info.has_key("title"): info['title'] = "untitled" - return """\ - - - - -ViewMTN: %(title)s - - - -

+class Template: + def header(self, info): + if not info.has_key("title"): info['title'] = "untitled" + return """\ + + + + + ViewMTN: %(title)s + + + + -

%(title)s

-""" % (info) +

%(title)s

+ """ % (info) + def footer(self, info): + return """\ + + """ % (time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime())) -def footer(info): - return """\ - - -""" % (time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime())) ============================================================ --- index.psp 91b20f95e6c81b15fa20307e27ab590700ea8200 +++ index.psp 7e7615f64309e31945a470f377f0acdf5e8ae832 @@ -1,22 +1,14 @@ <% -import config -import monotone import common -import urllib -import template -from template import header,footer -from monotone import Monotone from common import link psp.set_error_page("error.psp") info = { 'title' : "Branches" } -req.write(header(info)) +req.write(template.header(info)) hq = common.html_escape() -mt = Monotone(config.monotone, config.dbfile) branches = mt.branches() -del mt %> ============================================================ --- monotone.py bae49e4c0a167cf50c06a029d3f384d862d36741 +++ monotone.py ecef0d77b01add91f83b6cf4a04d60e9f1da7217 @@ -1,7 +1,8 @@ import utility -import string import urllib +import signal +import string import pipes import sets import sha @@ -34,23 +35,26 @@ return ''.join(map(lambda x: "%.2x" % int(x * 256), hls_to_rgb(hue, li, sat))) class Automation: - def __init__(self, mt, dbfile): - self.mt = mt - self.dbfile = dbfile - self.command = "%s --db=%s automate stdio" % (self.mt, pipes.quote(self.dbfile)) - #self.command = "/bin/cat" + def __init__(self, base_command): + self.command = "%s automate stdio" % (base_command) self.process = None def __del__(self): - if self.process: - try: - self.process.tochild.close() - self.process.fromchild.close() - self.process.wait() - except: pass + self.stop() self.process = None def start(self): self.process = popen2.Popen3(self.command) set_nonblocking(self.process.fromchild) + def stop(self): + if not self.process: return + try: + self.process.tochild.close() + self.process.fromchild.close() + if self.process.poll() == -1: + # the process is still running, so kill it. + os.kill(self.process.pid, signal.SIGKILL) + self.process.wait() + except: + pass def run(self, command, args): if self.process == None: self.start() enc = "l%d:%s" % (len(command), command) @@ -87,7 +91,7 @@ self.mt = mt self.dbfile = dbfile self.base_command = "%s --db=%s" % (self.mt, pipes.quote(self.dbfile)) - self.automate = Automation(self.mt, self.dbfile) + self.automate = Automation(self.base_command) def branches(self): result = utility.run_command(self.base_command + " ls branches") if result['exitcode'] != 0: @@ -208,7 +212,7 @@ rv = [] entry = None command = self.base_command + " log " + ' '.join(map(lambda x: '-r ' + pipes.quote(x), ids)) - if limit > 0: command += " --depth=%d" % (limit) + if limit > 0: command += " --last=%d" % (limit) iterator = utility.iter_command(command) for line in iterator: if dash_re.match(line): @@ -330,3 +334,4 @@ if len(self.result) == self.length: return (self.cmdnum, self.error, self.length, self.is_last, self.result) else: return None + ============================================================ --- revision.psp 51027eadc7443245e40030623274abe7202eef2b +++ revision.psp 6f463be44003bf7015196427c19b940a52be7cb1 @@ -1,13 +1,9 @@ <% import config import monotone import common import urllib -import template -from template import header,footer -from monotone import Monotone -reload(monotone) from common import link # @@ -26,11 +22,9 @@ if not monotone.is_valid_id(id): raise Exception("Specified revision ID is not valid.") -mt = Monotone(config.monotone, config.dbfile) - hq = common.html_escape() info = {'title' : "Revision %s" % (hq(id))} -req.write(header(info)) +req.write(template.header(info)) ancestry_limit = 10 ancestry_maximum = 100 ============================================================ --- tags.psp ebf8689665678fbcb9a90537d5f1fae8c2da73b8 +++ tags.psp df24079a00706530ae62c60e9224dddaf048b25c @@ -1,21 +1,16 @@ <% import config import monotone import common import urllib -import template -from template import header,footer -from monotone import Monotone from common import link psp.set_error_page("error.psp") info = { 'title' : "Tags" } -req.write(header(info)) +req.write(template.header(info)) hq = common.html_escape() -mt = Monotone(config.monotone, config.dbfile) - tags = mt.tags() %> ============================================================ --- tarofbranch.psp a213fcbd0ade73bb588d5d4b37bc9174b24299a4 +++ tarofbranch.psp 7559dc9f90f183396c4dff99903f5ea1f12e01cc @@ -1,12 +1,8 @@ <% -import config import monotone import common import urllib -import template -from template import header,footer -from monotone import Monotone from common import link psp.set_error_page("error.psp") @@ -21,8 +17,6 @@ # HEAD of a branch. If there are multiple heads, # present a choice. -mt = Monotone(config.monotone, config.dbfile) - heads = mt.heads(branch) if len(heads) == 0: raise Exception("No head ID can be determined for this branch.") @@ -33,7 +27,7 @@ else: hq = common.html_escape() info = {'title' : "Latest tar file of branch %s" % (hq(branch))} - req.write(header(info)) + req.write(template.header(info)) %>

The branch you have selected has multiple head revisions The head ============================================================ --- wrapper.py 7444ff00e621412e16056b61cc1e9663219b417b +++ wrapper.py c5ff5ec5ea7868257307f1cf0731868986d38772 @@ -1,15 +1,17 @@ from mod_python import apache,psp,util import config import monotone import mimetypes import urllib -from monotone import Monotone -import template +import os.path import tarfile import os import re +from monotone import Monotone +from html import Template + # paranoid sane_uri_re = re.compile('^\w+$') @@ -27,7 +29,7 @@ mime_type = None if form.has_key('path'): if mime_type == None: mime_type = mimetypes.guess_type(form['path'])[0] - req.headers_out["Content-Disposition"] = "attachment; filename=%s" % urllib.quote(form['path']) + req.headers_out["Content-Disposition"] = "attachment; filename=%s" % urllib.quote(os.path.split(form['path'])[-1]) if mime_type == None: mime_type = "text/plain" req.content_type = mime_type req.write(mt.file(id)) @@ -92,20 +94,39 @@ 'gettar.py' : get_tar } +def cleanup(req, vars): + mt = vars['mt'] + mt.automate.stop() + del mt + def handler(req): req.content_type = "text/plain" uri = req.uri slash = uri.rfind('/') if slash <> -1: uri = uri[slash+1:] + + # + # these handlers don't use PSP, for example if they need + # to return binary or otherwise pristine data to the user + # agent + # if handlers.has_key(uri): return handlers[uri](req) + + # + # PSP or 404 + # try: if uri.endswith('.psp') and sane_uri_re.match(uri[:-4]): req.content_type = "text/html" - template = psp.PSP(req, filename=uri) - template.run() + vars = { + 'mt' : Monotone(config.monotone, config.dbfile), + 'template' : Template() + } + req.register_cleanup(cleanup, (req, vars)) + instance = psp.PSP(req, filename=uri, vars=vars) + instance.run() return apache.OK except ValueError: return apache.HTTP_NOT_FOUND - return apache.HTTP_NOT_FOUND