Commits

Daniel Holth committed 9f546a9

move keys into signatures; add pep425tags (maintained externally)

Comments (0)

Files changed (8)

 #!/bin/sh
 # Vendorize pkg_resources and _markerlib from ../distribute/
 
+cp ../pep425/pep425tags.py wheel
+
 cp ../distribute/_markerlib/markers.py wheel/pkg_resources/markerlib.py
 cp ../distribute/pkg_resources.py wheel/pkg_resources/pkg_resources2.py
 2to3 ../distribute/pkg_resources.py -w -n -o wheel/pkg_resources
 mv wheel/pkg_resources/pkg_resources.py wheel/pkg_resources/pkg_resources3.py
 
+
 import shutil
 
 from wheel.decorator import reify
-from wheel.util import urlsafe_b64encode, from_json,\
-    urlsafe_b64decode, native, binary, generate_supported, \
-    HashingFile
+from wheel.util import (urlsafe_b64encode, from_json,
+    urlsafe_b64decode, native, binary, HashingFile)
 from wheel import signatures
 from wheel.pkginfo import read_pkg_info_bytes
 from wheel.util import open_for_csv
+from .pep425tags import get_supported as generate_supported
 
 # The next major version after this version of the 'wheel' tool:
 VERSION_TOO_HIGH = (1, 0)

wheel/keys.py

-"""Store and retrieve wheel signing / verifying keys.
-
-Given a scope (a package name, + meaning "all packages", or - meaning 
-"no packages"), return a list of verifying keys that are trusted for that 
-scope.
-
-Given a package name, return a list of (scope, key) suggested keys to sign
-that package (only the verifying keys; the private signing key is stored
-elsewhere).
-
-Keys here are represented as urlsafe_b64encoded strings with no padding.
-
-Tentative command line interface:
-
-# list trusts
-wheel trust
-# trust a particular key for all
-wheel trust + key
-# trust key for beaglevote
-wheel trust beaglevote key
-# stop trusting a key for all
-wheel untrust + key
-
-# generate a key pair
-wheel keygen
-
-# import a signing key from a file
-wheel import keyfile
-
-# export a signing key
-wheel export key
-"""
-
-import json
-import os.path
-from wheel.util import native, load_config_paths, save_config_path
-
-class WheelKeys(object):
-    SCHEMA = 1
-    CONFIG_NAME = 'wheel.json'
-    
-    def __init__(self):
-        self.data = {'signers':[], 'verifiers':[]}
-        
-    def load(self):
-        # XXX JSON is not a great database
-        for path in load_config_paths('wheel'):
-            conf = os.path.join(native(path), self.CONFIG_NAME)
-            if os.path.exists(conf):
-                with open(conf, 'r') as infile:
-                    self.data = json.load(infile)
-                    for x in ('signers', 'verifiers'):
-                        if not x in self.data:
-                            self.data[x] = []
-                    if 'schema' not in self.data:
-                        self.data['schema'] = self.SCHEMA
-                    elif self.data['schema'] != self.SCHEMA:
-                        raise ValueError(
-                            "Bad wheel.json version {}, expected {}".format(
-                                self.data['schema'], self.SCHEMA))
-                break
-        return self
-
-    def save(self):
-        # Try not to call this a very long time after load() 
-        path = save_config_path('wheel')
-        conf = os.path.join(native(path), self.CONFIG_NAME)
-        with open(conf, 'w+') as out:
-            json.dump(self.data, out, indent=2)
-        return self
-    
-    def trust(self, scope, vk):
-        """Start trusting a particular key for given scope."""
-        self.data['verifiers'].append({'scope':scope, 'vk':vk})
-        return self
-    
-    def untrust(self, scope, vk):
-        """Stop trusting a particular key for given scope."""
-        self.data['verifiers'].remove({'scope':scope, 'vk':vk})
-        return self
-        
-    def trusted(self, scope=None):
-        """Return list of [(scope, trusted key), ...] for given scope."""
-        trust = [(x['scope'], x['vk']) for x in self.data['verifiers'] if x['scope'] in (scope, '+')]
-        trust.sort(key=lambda x: x[0])
-        trust.reverse()
-        return trust
-    
-    def signers(self, scope):
-        """Return list of signing key(s)."""
-        sign = [(x['scope'], x['vk']) for x in self.data['signers'] if x['scope'] in (scope, '+')]
-        sign.sort(key=lambda x: x[0])
-        sign.reverse()
-        return sign
-    
-    def add_signer(self, scope, vk):
-        """Remember verifying key vk as being valid for signing in scope."""
-        self.data['signers'].append({'scope':scope, 'vk':vk})
-    

wheel/pep425tags.py

+"""Generate and work with PEP 425 Compatibility Tags."""
+
+import sys
+
+try:
+    import sysconfig
+except ImportError:  # pragma nocover
+    # Python < 2.7
+    import distutils.sysconfig as sysconfig
+import distutils.util
+
+
+def get_abbr_impl():
+    """Return abbreviated implementation name."""
+    if hasattr(sys, 'pypy_version_info'):
+        pyimpl = 'pp'
+    elif sys.platform.startswith('java'):
+        pyimpl = 'jy'
+    elif sys.platform == 'cli':
+        pyimpl = 'ip'
+    else:
+        pyimpl = 'cp'
+    return pyimpl
+
+
+def get_impl_ver():
+    """Return implementation version."""
+    impl_ver = sysconfig.get_config_var("py_version_nodot")
+    if not impl_ver:
+        impl_ver = ''.join(map(str, sys.version_info[:2]))
+    return impl_ver
+
+
+def get_platform():
+    """Return our platform name 'win32', 'linux_x86_64'"""
+    # XXX remove distutils dependency
+    return distutils.util.get_platform().replace('.', '_').replace('-', '_')
+
+
+def get_supported(versions=None):
+    """Return a list of supported tags for each version specified in
+    `versions`.
+
+    :param versions: a list of string versions, of the form ["33", "32"], 
+        or None. The first version will be assumed to support our ABI.
+    """
+    supported = []
+    
+    # Versions must be given with respect to the preference
+    if versions is None:
+        versions = []
+        major = sys.version_info[0]
+        # Support all previous minor Python versions.
+        for minor in range(sys.version_info[1], -1, -1):
+            versions.append(''.join(map(str, (major, minor))))
+            
+    impl = get_abbr_impl()
+    
+    abis = []
+
+    soabi = sysconfig.get_config_var('SOABI')
+    if soabi and soabi.startswith('cpython-'):
+        abis[0:0] = ['cp' + soabi.split('-', 1)[-1]]
+ 
+    abi3s = set()
+    import imp
+    for suffix in imp.get_suffixes():
+        if suffix[0].startswith('.abi'):
+            abi3s.add(suffix[0].split('.', 2)[1])
+
+    abis.extend(sorted(list(abi3s)))
+
+    abis.append('none')
+
+    arch = get_platform()
+    
+    # Current version, current API (built specifically for our Python):
+    for abi in abis:
+        supported.append(('%s%s' % (impl, versions[0]), abi, arch))
+            
+    # No abi / arch, but requires our implementation:
+    for i, version in enumerate(versions):
+        supported.append(('%s%s' % (impl, version), 'none', 'any'))
+        if i == 0:
+            # Tagged specifically as being cross-version compatible 
+            # (with just the major version specified)
+            supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any')) 
+            
+    # No abi / arch, generic Python
+    for i, version in enumerate(versions):
+        supported.append(('py%s' % (version,), 'none', 'any'))
+        if i == 0:
+            supported.append(('py%s' % (version[0]), 'none', 'any'))
+        
+    return supported
+
+

wheel/signatures/keys.py

+"""Store and retrieve wheel signing / verifying keys.
+
+Given a scope (a package name, + meaning "all packages", or - meaning 
+"no packages"), return a list of verifying keys that are trusted for that 
+scope.
+
+Given a package name, return a list of (scope, key) suggested keys to sign
+that package (only the verifying keys; the private signing key is stored
+elsewhere).
+
+Keys here are represented as urlsafe_b64encoded strings with no padding.
+
+Tentative command line interface:
+
+# list trusts
+wheel trust
+# trust a particular key for all
+wheel trust + key
+# trust key for beaglevote
+wheel trust beaglevote key
+# stop trusting a key for all
+wheel untrust + key
+
+# generate a key pair
+wheel keygen
+
+# import a signing key from a file
+wheel import keyfile
+
+# export a signing key
+wheel export key
+"""
+
+import json
+import os.path
+from wheel.util import native, load_config_paths, save_config_path
+
+class WheelKeys(object):
+    SCHEMA = 1
+    CONFIG_NAME = 'wheel.json'
+    
+    def __init__(self):
+        self.data = {'signers':[], 'verifiers':[]}
+        
+    def load(self):
+        # XXX JSON is not a great database
+        for path in load_config_paths('wheel'):
+            conf = os.path.join(native(path), self.CONFIG_NAME)
+            if os.path.exists(conf):
+                with open(conf, 'r') as infile:
+                    self.data = json.load(infile)
+                    for x in ('signers', 'verifiers'):
+                        if not x in self.data:
+                            self.data[x] = []
+                    if 'schema' not in self.data:
+                        self.data['schema'] = self.SCHEMA
+                    elif self.data['schema'] != self.SCHEMA:
+                        raise ValueError(
+                            "Bad wheel.json version {}, expected {}".format(
+                                self.data['schema'], self.SCHEMA))
+                break
+        return self
+
+    def save(self):
+        # Try not to call this a very long time after load() 
+        path = save_config_path('wheel')
+        conf = os.path.join(native(path), self.CONFIG_NAME)
+        with open(conf, 'w+') as out:
+            json.dump(self.data, out, indent=2)
+        return self
+    
+    def trust(self, scope, vk):
+        """Start trusting a particular key for given scope."""
+        self.data['verifiers'].append({'scope':scope, 'vk':vk})
+        return self
+    
+    def untrust(self, scope, vk):
+        """Stop trusting a particular key for given scope."""
+        self.data['verifiers'].remove({'scope':scope, 'vk':vk})
+        return self
+        
+    def trusted(self, scope=None):
+        """Return list of [(scope, trusted key), ...] for given scope."""
+        trust = [(x['scope'], x['vk']) for x in self.data['verifiers'] if x['scope'] in (scope, '+')]
+        trust.sort(key=lambda x: x[0])
+        trust.reverse()
+        return trust
+    
+    def signers(self, scope):
+        """Return list of signing key(s)."""
+        sign = [(x['scope'], x['vk']) for x in self.data['signers'] if x['scope'] in (scope, '+')]
+        sign.sort(key=lambda x: x[0])
+        sign.reverse()
+        return sign
+    
+    def add_signer(self, scope, vk):
+        """Remember verifying key vk as being valid for signing in scope."""
+        self.data['signers'].append({'scope':scope, 'vk':vk})
+    

wheel/test/test_keys.py

 import unittest
 import json
 
-from wheel import keys
+from wheel.signatures import keys
 
 wheel_json = """
 {
         self.wk.save()
         self.wk.load()
     
-    
+    

wheel/tool/__init__.py

 import os
 import hashlib
 import sys
-import wheel.install
 import wheel.signatures
 import json
 from glob import iglob
 from ..util import urlsafe_b64decode, urlsafe_b64encode, native, binary
 from ..wininst2wheel import bdist_wininst2wheel
 from ..egg2wheel import egg2wheel
+from ..install import WheelFile
 
 import argparse
 
 def keygen():
     """Generate a public/private key pair."""
     try:
-        import wheel.keys
+        from ..signatures import keys
         import keyring
     except ImportError:
         raise Exception("Install wheel[signatures] (keyring, dirspec) for signatures")
 def sign(wheelfile, replace=False):
     """Sign a wheel"""
     try:
-        import wheel.keys
+        from ..signatures import keys
         import keyring
     except ImportError:
         raise Exception("Install wheel[signatures] (keyring, dirspec) for signatures")
     ed25519ll = wheel.signatures.get_ed25519ll()
     
     wf = wheel.install.WheelFile(wheelfile, append=True)
-    wk = wheel.keys.WheelKeys().load()
+    wk = keys.WheelKeys().load()
     
     name = wf.parsed_filename.group('name')
     sign_with = wk.signers(name)[0]
 import base64
 import json
 import hashlib
-try:
-    import sysconfig
-except ImportError:  # pragma nocover
-    # Python < 2.7
-    import distutils.sysconfig as sysconfig
-from distutils.util import get_platform
+
+from .pep425tags import (get_abbr_impl, get_impl_ver, 
+                         get_supported as generate_supported)
 
 __all__ = ['urlsafe_b64encode', 'urlsafe_b64decode', 'utf8', 'to_json',
            'from_json', 'generate_supported', 'get_abbr_impl', 'get_impl_ver',
         if isinstance(s, str):
             return s.encode('ascii')
 
-
-def get_abbr_impl():
-    """Return abbreviated implementation name."""
-    if hasattr(sys, 'pypy_version_info'):
-        pyimpl = 'pp'
-    elif sys.platform.startswith('java'):
-        pyimpl = 'jy'
-    elif sys.platform == 'cli':
-        pyimpl = 'ip'
-    else:
-        pyimpl = 'cp'
-    return pyimpl
-
-
-def get_impl_ver():
-    '''Return implementation version.'''
-    impl_ver = sysconfig.get_config_var("py_version_nodot")
-    if not impl_ver:
-        impl_ver = ''.join(map(str, sys.version_info[:2]))
-    return impl_ver
-
-
-def generate_supported(versions=None):
-    '''Generate supported tags for each version specified in `versions`.
-
-    Versions must be given with respect to preference from best to worst.
-    If `versions` is None, then the current version is assumed.
-    Returned tags are sorted from best-matching tags to worst. All tags
-    returned should be compatible with the machine.
-    '''
-    supported = []
-    
-    # Versions must be given with respect to the preference
-    if versions is None:
-        versions = []
-        major = sys.version_info[0]
-        # Support all previous minor Python versions.
-        for minor in range(sys.version_info[1], -1, -1):
-            versions.append(''.join(map(str, (major, minor))))
-            
-    impl = get_abbr_impl()
-    
-    abis = []
-
-    soabi = sysconfig.get_config_var('SOABI')
-    if soabi and soabi.startswith('cpython-'):
-        abis[0:0] = ['cp' + soabi.split('-', 1)[-1]]
- 
-    abi3s = set()
-    import imp
-    for suffix in imp.get_suffixes():
-        if suffix[0].startswith('.abi'):
-            abi3s.add(suffix[0].split('.', 2)[1])
-
-    abis.extend(sorted(list(abi3s)))
-
-    abis.append('none')
-
-    arch = get_platform().replace('.', '_').replace('-', '_')
-    
-    # Current version, current API (built specifically for our Python):
-    for abi in abis:
-        supported.append(('%s%s' % (impl, versions[0]), abi, arch))
-            
-    # No abi / arch, but requires our implementation:
-    for i, version in enumerate(versions):
-        supported.append(('%s%s' % (impl, version), 'none', 'any'))
-        if i == 0:
-            # Tagged specifically as being cross-version compatible 
-            # (with just the major version specified)
-            supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any')) 
-            
-    # No abi / arch, generic Python
-    for i, version in enumerate(versions):
-        supported.append(('py%s' % (version,), 'none', 'any'))
-        if i == 0:
-            supported.append(('py%s' % (version[0]), 'none', 'any'))
-        
-    return supported
-
-
 class HashingFile(object):
     def __init__(self, fd, hashtype='sha256'):
         self.fd = fd