# # # patch "error.psp" # from [e1defd5a7a1469119dcbe07f0624e3412c394a03] # to [312eeeb8ea00ab36b0b5d64eb8fa5b65e75cd418] # # patch "file.psp" # from [b18003b58deaf7a838a644a0757d57c5e8b69f91] # to [f19f6fefe38a97ca636705f070f4535534947a48] # # patch "fileinbranch.psp" # from [14051e609852522f4eba270632b444fc470768a8] # to [4f01b7f1260ca7a9c756047ea0dcfaa5fabc4b0c] # # patch "manifest.psp" # from [707922f63bdcc200ab716a047b3116afb0ffccf2] # to [722b15a5c3eeca08a8415264c691f2f1966b0cbc] # # patch "monotone.py" # from [bdf8d159c331916c691858713488beacd50e9cc2] # to [f8211dca24b2b5e48c89d5e88d95388a683282b7] # # patch "revision.psp" # from [b0be5ff714ff6ecdf9f86b4dd34d8d1fa8044d0e] # to [b5b23a31a00ed137eaa2d46681966ad758efc90b] # # patch "wrapper.py" # from [a3b890f3aa3d092d6ab1c8e9d3d401e83ddfe316] # to [dbbc871353ddfec1b56bf57b743a6b5cd70688c2] # ============================================================ --- error.psp e1defd5a7a1469119dcbe07f0624e3412c394a03 +++ error.psp 312eeeb8ea00ab36b0b5d64eb8fa5b65e75cd418 @@ -14,7 +14,7 @@ # a program error e_type, e_value, e_traceback = sys.exc_info() -if (str(e_type) == "exceptions.Exception"): +if (str(e_type) == "exceptions.Exceptionf"): # this is a deliberate exception, pretty print %> ============================================================ --- file.psp b18003b58deaf7a838a644a0757d57c5e8b69f91 +++ file.psp f19f6fefe38a97ca636705f070f4535534947a48 @@ -34,11 +34,7 @@ certs = mt.certs(id) branches = common.extract_cert_from_certs(certs, "branch", as_list=True) -revision = mt.revision(id) -if not revision.has_key('new_manifest'): - raise Exception("There is no manifest in this revision ID.") -manifest_id = revision['new_manifest'][0][1] -manifest = mt.manifest(manifest_id) +manifest = [(t[3], t[1]) for t in mt.manifest_of(id)['file']] matching_file_id = None for file_id, filename in manifest: ============================================================ --- fileinbranch.psp 14051e609852522f4eba270632b444fc470768a8 +++ fileinbranch.psp 4f01b7f1260ca7a9c756047ea0dcfaa5fabc4b0c @@ -27,9 +27,7 @@ # match PATH and their file ID. file_version = {} for id in heads: - revision = mt.revision(id) - manifest_id = revision['new_manifest'][0][1] - file_revisions = filter(lambda x: x[1] == path, mt.manifest(manifest_id)) + file_revisions = filter(lambda x: x[1] == path, mt.manifest_of(id)['file']) if len(file_revisions) > 1: raise Exception("More than one file matches path?") elif len(file_revisions) == 1: ============================================================ --- manifest.psp 707922f63bdcc200ab716a047b3116afb0ffccf2 +++ manifest.psp 722b15a5c3eeca08a8415264c691f2f1966b0cbc @@ -31,11 +31,7 @@ if path.endswith('/'): path = path[-1:] certs = mt.certs(id) -revision = mt.revision(id) -if not revision.has_key('new_manifest'): - raise Exception("There is no manifest in this revision ID.") -manifest_id = revision['new_manifest'][0][1] -manifest = mt.manifest(manifest_id) +manifest = [(t[3], t[1]) for t in mt.manifest_of(id)['file']] link_components = "" components = [''] @@ -60,7 +56,7 @@

-All <%=len(manifest)%> files in this manifest can be downloaded together in a <%=link("tar", manifest_id, "tar archive")%>. +All <%=len(manifest)%> files in this manifest can be downloaded together in a <%=link("tar", id, "tar archive")%>.

<% ============================================================ --- monotone.py bdf8d159c331916c691858713488beacd50e9cc2 +++ monotone.py f8211dca24b2b5e48c89d5e88d95388a683282b7 @@ -132,13 +132,16 @@ def basic_io_parser(self, data): """returns a list of lists of (key, value) tuples. hashes are returned with []s around them; strings are returned raw.""" + + ### fixme, really needs a rewrite + def unescape_string_value(str): rv = "" is_terminated = False in_escape = False if str[0] != '"': - raise Exception("basic_io parse error; not a string.") - for c in str[1:]: + raise Exception("basic_io parse error; not a string: ;%s; (%d)" % (str, len(str))) + for idx, c in enumerate(str[1:]): if in_escape: if c != '\\' and c != '\"': raise Exception(r'basic_io parse error; expected \" or \\') @@ -148,12 +151,11 @@ if c == '\\': in_escape = True elif c == '"': - if is_terminated: - raise Exception("basic_io parse error; string ends twice!") is_terminated = True + return is_terminated, str[idx+2:], rv else: rv += c - return is_terminated, rv + return is_terminated, '', rv # 14:46 < tbrownaw> list>>, with the outer list divided according to # what item starts a stanza? @@ -166,9 +168,9 @@ for line in data.split('\n'): if ongoing_string != None: ongoing_string += '\n' + line - is_terminated, e_value = unescape_string_value(ongoing_string) + is_terminated, value_buffer, e_value = unescape_string_value(ongoing_string) if is_terminated: - stanza += [key, e_value] + stanza.append(e_value) ongoing_string = None continue @@ -186,9 +188,22 @@ m = basic_io_string_re.match(line) if m: key, value = m.groups() - is_terminated, e_value = unescape_string_value(value) - if not is_terminated: ongoing_string = value - else: stanza += [key, e_value] + # consume values from the buffer until none remain, + # or we're stuck waiting for a multi-line value to + # be concluded + + stanza.append(key) + value_buffer = value + while value_buffer: + is_terminated, value_buffer, e_value = unescape_string_value(value_buffer) + if is_terminated == True: + stanza.append(e_value) + else: + break + value_buffer = value_buffer.strip() + + if not is_terminated: + ongoing_string = value continue return rv def certs(self, id): @@ -235,16 +250,13 @@ raise Exception("Unable to get children of %s: %s" % (id, result)) else: return filter(None, result.split('\n')) - def manifest(self, id): - error, result = self.automate.run('get_manifest', [id]) + def manifest_of(self, id): + error, result = self.automate.run('get_manifest_of', [id]) if error != 0: raise Exception("Unable to get manifest %s: %s" % (id, result)) - rv = [] - for line in result.split('\n'): - m = manifest_entry_re.match(line) - if not m: continue - rv.append(m.groups()) - return rv + + stanzas = self.basic_io_parser(result) + return stanzas def file(self, id): error, result = self.automate.run('get_file', [id]) if error != 0: @@ -273,7 +285,7 @@ def log(self, ids, limit=0): rv = [] entry = None - command = self.base_command + " log " + ' '.join(map(lambda x: '-r ' + pipes.quote(x), ids)) + command = self.base_command + " --merges log " + ' '.join(map(lambda x: '-r ' + pipes.quote(x), ids)) if limit > 0: command += " --last=%d" % (limit) iterator = utility.iter_command(command) for line in iterator: ============================================================ --- revision.psp b0be5ff714ff6ecdf9f86b4dd34d8d1fa8044d0e +++ revision.psp b5b23a31a00ed137eaa2d46681966ad758efc90b @@ -111,7 +111,7 @@ (link("file", [id, fname], fname), diff_links) elif type == "old_revision": - old_revision, old_manifest = stanza[1], stanza[3] + old_revision = stanza[1] old_revisions.append(old_revision) value += 'Old revision is: %s (%s)
' % \ (link("revision", old_revision), ============================================================ --- wrapper.py a3b890f3aa3d092d6ab1c8e9d3d401e83ddfe316 +++ wrapper.py dbbc871353ddfec1b56bf57b743a6b5cd70688c2 @@ -100,20 +100,14 @@ rv['author'] = last_author elif class_name == "manifestLink": rv['type'] = 'manifest' - revision = mt.revision(query['id']) - if revision.has_key('new_manifest'): - manifest_id = revision['new_manifest'][0][1] - manifest = mt.manifest(manifest_id) - dir_seen = {} # would use a set, but need python2.4 really - for file_id, filename in manifest: - fsp = filename.rsplit('/', 1) - if len(fsp) == 2 and not dir_seen.has_key(fsp[1]): - dir_seen[fsp[1]] = True - rv['file_count'] = len(manifest) - rv['directory_count'] = len(dir_seen.keys()) + 1 # root dir - else: - rv['file_count'] = 0 - rv['directory_count'] = 0 + dir_seen = {} # would use a set, but need python2.4 really + rv['file_count'] = 0 + for file_id, filename in ((t[3], t[1]) for t in mt.manifest_of(query['id'])['file']): + fsp = filename.rsplit('/', 1) + if len(fsp) == 2 and not dir_seen.has_key(fsp[1]): + dir_seen[fsp[1]] = True + rv['file_count'] += 1 + rv['directory_count'] = len(dir_seen.keys()) + 1 # root dir req.write(writer.write(rv)) return apache.OK @@ -142,7 +136,7 @@ req.content_type = 'application/x-tar; charset=utf-8' req.headers_out["Content-Disposition"] = "attachment; filename=%s" % tar_file_name tf = tarfile.open(mode="w", fileobj=tar_file) - for fileid, filename in mt.manifest(id): + for fileid, filename in ((t[3], t[1]) for t in mt.manifest_of(id)['file']): data = mt.file(fileid) ti = tarfile.TarInfo() ti.mode = 00700