releasing/blocks/framework/src/Blocks/gpg.py
changeset 632 934f9131337b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/releasing/blocks/framework/src/Blocks/gpg.py	Thu Sep 02 15:02:14 2010 +0800
@@ -0,0 +1,132 @@
+#
+# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# Wrapper for gpg
+#
+
+''' gpg command wrapper '''
+
+import sys
+from subprocess import Popen, PIPE
+from collections import namedtuple
+import logging
+
+_GNUPGPREFIX = "[GNUPG:] "
+_GNUPGGOODSIG = "GOODSIG"
+_GNUPGBADSIG = "BADSIG"
+_GNUPGNOPUBKEY = "NO_PUBKEY"
+_GNUPGKEYEXPIRED = "KEYEXPIRED"
+_GNUPGREVKEYSIG = "REVKEYSIG"
+
+class GpgStatusCode(object):
+    VERIFIED, BADSIG, NO_PUBKEY, KEYEXPIRED, REVKEYSIG = range(5)
+
+VerifyInfo = namedtuple("VerifyInfo", "name")
+VerifyStatus = namedtuple("VerifyStatus", "code, info")
+
+#define GNUPGVALIDSIG "[GNUPG:] VALIDSIG"
+#define GNUPGNODATA "[GNUPG:] NODATA"
+
+class GpgError(Exception):
+    """ Gpg exited with error """
+    def __init__(self, errorcode, output):
+        Exception.__init__(self, "Gpg failed with error code %s" % errorcode)
+        self.errorcode = errorcode
+        self.output = output.strip()
+
+def sign(sourcePath, outputPath, homedir=None, batch=False, passfile=None):
+    '''
+    Create a gpg signature of a file.
+
+    sign() has two modes: file and pipe. File: Specify sourcePath and outputPath
+    as strings to create signature of file sourcePath in file outputPath. Pipe:
+    Specify sourcePath as readable object and outputPath as None. The signature
+    is the return value.
+
+    Use a combination of batch, homedir and passfile to eliminate the need for
+    interaction.
+
+    File mode::
+        gpg.sign("/my/file", "/my/file.gpg")
+
+    Pipe mode without interaction::
+        f = open("/my/file", "rb")
+        key = gpg.sign(f, None, "/my/passwordless/keydir", True)
+        f.close()
+
+    @param sourcePath: Path of the file to sign, or pipe to read the file from
+    @type sourcePath: String or file-like object
+    @param outputPath: Path to write signature to, or None in pipe mode
+    @type outputPath: String or None
+    @param homedir: Directory to read keyfile from
+    @type homedir: String
+    @param batch: Whether to use I{--batch} with gpg command
+    @type batch: Boolean
+    @param passfile: Optional passphrase file to use with the key
+    @type passfile: String
+    '''
+    cmdstr = "gpg -abs"
+    if homedir:
+        cmdstr += ' --homedir "%s"' % homedir
+    if batch:
+        cmdstr += ' --batch'
+        pStdin = None
+    else:
+        pStdin = sys.stdin
+    if passfile:
+        cmdstr += ' --passphrase-file "%s"' % passfile
+
+    if isinstance(outputPath, basestring) and isinstance(sourcePath, basestring):
+        cmdstr += ' -o "%s" "%s"' % (outputPath, sourcePath)
+        p = Popen(cmdstr, shell=True, stdin=pStdin, stdout=PIPE, stderr=PIPE)
+    else:
+        assert (sourcePath and hasattr(sourcePath, "read")), "sourcePath not file-like object!"
+        p = Popen(cmdstr, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        blockSize = 32*1024
+        buf = sourcePath.read(blockSize)
+        while buf:
+            try:
+                p.stdin.write(buf)
+            except IOError:
+                break
+            buf = sourcePath.read(blockSize)
+    (stdoutput, stderror) = p.communicate()
+    if stderror is None:
+        stderror = ""
+    if p.returncode != 0:
+        raise GpgError(p.returncode, stderror)
+    return stdoutput
+
+def verify(signFilePath, signedFilePath, homedir=None):
+    cmdstr = ('gpgv --keyring pubring.gpg --ignore-time-conflict --status-fd 2 %s "%s" "%s"' %
+        ('--homedir "%s"' % homedir if homedir else "", signFilePath, signedFilePath))
+    logging.debug("GPG running: %s", cmdstr)
+    p = Popen(cmdstr, shell=True, stdin=sys.stdin, stdout=PIPE, stderr=PIPE)
+    (stdoutput, stderror) = p.communicate()
+    logging.debug("GPG stdout: %s", stdoutput)
+    logging.debug("GPG stderror (status): %s", stderror)
+    for line in stderror.splitlines():
+        if line.startswith(_GNUPGPREFIX):
+            line = line.replace(_GNUPGPREFIX, "", 1)
+            (statusString, _, info) = line.partition(" ")
+            status = {_GNUPGGOODSIG: GpgStatusCode.VERIFIED,
+                      _GNUPGBADSIG: GpgStatusCode.BADSIG,
+                      _GNUPGNOPUBKEY: GpgStatusCode.NO_PUBKEY,
+                      _GNUPGKEYEXPIRED: GpgStatusCode.KEYEXPIRED,
+                      _GNUPGREVKEYSIG: GpgStatusCode.REVKEYSIG}.get(statusString)
+            if status is not None:
+                name = info.partition(" ")[2]
+                return VerifyStatus(status, VerifyInfo(name))
+    if p.returncode != 0:
+        raise GpgError(p.returncode, stdoutput)
\ No newline at end of file