Mercurial > hg > mercurial-crew-with-dirclash
view hgext/gpg.py @ 1598:14d1f1868bf6
cleanup of revlog.group when repository is local
revlog.group cached every chunk from the revlog, the behaviour was
needed to minimize the roundtrip with old-http.
We now cache the revlog data ~4MB at a time.
The memory used server side when pulling goes down to 35Mo maximum
whereas without the patch more than 160Mo was used when cloning the linux kernel
repository.
The time used by cloning is higher mainly because of the check in revlog.revision.
before
110.25user 20.90system 2:52.00elapsed 76%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+708707minor)pagefaults 0swaps
after
117.56user 18.86system 2:50.43elapsed 80%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+748366minor)pagefaults 0swaps
author | Benoit Boissinot <benoit.boissinot@ens-lyon.org> |
---|---|
date | Tue, 27 Dec 2005 13:09:49 -0600 |
parents | 347c44611348 |
children | ff339dd21976 |
line wrap: on
line source
import os, tempfile, binascii, errno from mercurial import util from mercurial import node as hgnode class gpg: def __init__(self, path, key=None): self.path = path self.key = (key and " --local-user \"%s\"" % key) or "" def sign(self, data): gpgcmd = "%s --sign --detach-sign%s" % (self.path, self.key) return util.filter(data, gpgcmd) def verify(self, data, sig): """ returns of the good and bad signatures""" try: fd, sigfile = tempfile.mkstemp(prefix="hggpgsig") fp = os.fdopen(fd, 'wb') fp.write(sig) fp.close() fd, datafile = tempfile.mkstemp(prefix="hggpgdata") fp = os.fdopen(fd, 'wb') fp.write(data) fp.close() gpgcmd = "%s --logger-fd 1 --status-fd 1 --verify \"%s\" \"%s\"" % (self.path, sigfile, datafile) #gpgcmd = "%s --status-fd 1 --verify \"%s\" \"%s\"" % (self.path, sigfile, datafile) ret = util.filter("", gpgcmd) except: for f in (sigfile, datafile): try: if f: os.unlink(f) except: pass raise keys = [] key, fingerprint = None, None err = "" for l in ret.splitlines(): # see DETAILS in the gnupg documentation # filter the logger output if not l.startswith("[GNUPG:]"): continue l = l[9:] if l.startswith("ERRSIG"): err = "error while verifying signature" break elif l.startswith("VALIDSIG"): # fingerprint of the primary key fingerprint = l.split()[10] elif (l.startswith("GOODSIG") or l.startswith("EXPSIG") or l.startswith("EXPKEYSIG") or l.startswith("BADSIG")): if key is not None: keys.append(key + [fingerprint]) key = l.split(" ", 2) fingerprint = None if err: return err, [] if key is not None: keys.append(key + [fingerprint]) return err, keys def newgpg(ui, **opts): gpgpath = ui.config("gpg", "cmd", "gpg") gpgkey = opts.get('key') if not gpgkey: gpgkey = ui.config("gpg", "key", None) return gpg(gpgpath, gpgkey) def check(ui, repo, rev): """verify all the signatures there may be for a particular revision""" mygpg = newgpg(ui) rev = repo.lookup(rev) hexrev = hgnode.hex(rev) keys = [] def addsig(fn, ln, l): if not l: return n, v, sig = l.split(" ", 2) if n == hexrev: data = node2txt(repo, rev, v) sig = binascii.a2b_base64(sig) err, k = mygpg.verify(data, sig) if not err: keys.append((k, fn, ln)) else: ui.warn("%s:%d %s\n" % (fn, ln , err)) fl = repo.file(".hgsigs") h = fl.heads() h.reverse() # read the heads for r in h: ln = 1 for l in fl.read(r).splitlines(): addsig(".hgsigs|%s" % hgnode.short(r), ln, l) ln +=1 try: # read local signatures ln = 1 f = repo.opener("localsigs") for l in f: addsig("localsigs", ln, l) ln +=1 except IOError: pass if not keys: ui.write("%s not signed\n" % hgnode.short(rev)) return valid = [] # warn for expired key and/or sigs for k, fn, ln in keys: prefix = "%s:%d" % (fn, ln) for key in k: if key[0] == "BADSIG": ui.write("%s Bad signature from \"%s\"\n" % (prefix, key[2])) continue if key[0] == "EXPSIG": ui.write("%s Note: Signature has expired" " (signed by: \"%s\")\n" % (prefix, key[2])) elif key[0] == "EXPKEYSIG": ui.write("%s Note: This key has expired" " (signed by: \"%s\")\n" % (prefix, key[2])) valid.append((key[1], key[2], key[3])) # print summary ui.write("%s is signed by:\n" % hgnode.short(rev)) for keyid, user, fingerprint in valid: role = getrole(ui, fingerprint) ui.write(" %s (%s)\n" % (user, role)) def getrole(ui, fingerprint): return ui.config("gpg", fingerprint, "no role defined") def sign(ui, repo, *revs, **opts): """add a signature for the current tip or a given revision""" mygpg = newgpg(ui, **opts) sigver = "0" sigmessage = "" if revs: nodes = [repo.lookup(n) for n in revs] else: nodes = [repo.changelog.tip()] for n in nodes: hexnode = hgnode.hex(n) ui.write("Signing %d:%s\n" % (repo.changelog.rev(n), hgnode.short(n))) # build data data = node2txt(repo, n, sigver) sig = mygpg.sign(data) if not sig: raise util.Abort("Error while signing") sig = binascii.b2a_base64(sig) sig = sig.replace("\n", "") sigmessage += "%s %s %s\n" % (hexnode, sigver, sig) # write it if opts['local']: repo.opener("localsigs", "ab").write(sigmessage) return (c, a, d, u) = repo.changes() for x in (c, a, d, u): if ".hgsigs" in x and not opts["force"]: raise util.Abort("working copy of .hgsigs is changed " "(please commit .hgsigs manually" "or use --force)") repo.wfile(".hgsigs", "ab").write(sigmessage) if repo.dirstate.state(".hgsigs") == '?': repo.add([".hgsigs"]) if opts["no_commit"]: return message = opts['message'] if not message: message = "\n".join(["Added signature for changeset %s" % hgnode.hex(n) for n in nodes]) try: repo.commit([".hgsigs"], message, opts['user'], opts['date']) except ValueError, inst: raise util.Abort(str(inst)) def node2txt(repo, node, ver): """map a manifest into some text""" if ver == "0": return "%s\n" % hgnode.hex(node) else: util.Abort("unknown signature version") cmdtable = { "sign": (sign, [('l', 'local', None, "make the signature local"), ('f', 'force', None, "sign even if the sigfile is modified"), ('', 'no-commit', None, "do not commit the sigfile after signing"), ('m', 'message', "", "commit message"), ('d', 'date', "", "date code"), ('u', 'user', "", "user"), ('k', 'key', "", "the key id to sign with")], "hg sign [OPTION]... REVISIONS"), "sigcheck": (check, [], 'hg sigcheck REVISION') }