~ibmcharmers/charms/xenial/ibm-cinder-storwize-svc/trunk

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/wheel/tool/__init__.py

  • Committer: Ankammarao
  • Date: 2017-03-06 05:11:42 UTC
  • Revision ID: achittet@in.ibm.com-20170306051142-dpg27z4es1k56hfn
Marked tests folder executable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Wheel command-line utility.
 
3
"""
 
4
 
 
5
import os
 
6
import hashlib
 
7
import sys
 
8
import json
 
9
 
 
10
from glob import iglob
 
11
from .. import signatures
 
12
from ..util import (urlsafe_b64decode, urlsafe_b64encode, native, binary,
 
13
                    matches_requirement)
 
14
from ..install import WheelFile, VerifyingZipFile
 
15
from ..paths import get_install_command
 
16
 
 
17
def require_pkgresources(name):
 
18
    try:
 
19
        import pkg_resources
 
20
    except ImportError:
 
21
        raise RuntimeError("'{0}' needs pkg_resources (part of setuptools).".format(name))
 
22
 
 
23
import argparse
 
24
 
 
25
class WheelError(Exception): pass
 
26
 
 
27
# For testability
 
28
def get_keyring():
 
29
    try:
 
30
        from ..signatures import keys
 
31
        import keyring
 
32
        assert keyring.get_keyring().priority
 
33
    except (ImportError, AssertionError):
 
34
        raise WheelError("Install wheel[signatures] (requires keyring, keyrings.alt, pyxdg) for signatures.")
 
35
    return keys.WheelKeys, keyring
 
36
 
 
37
def keygen(get_keyring=get_keyring):
 
38
    """Generate a public/private key pair."""
 
39
    WheelKeys, keyring = get_keyring()
 
40
 
 
41
    ed25519ll = signatures.get_ed25519ll()
 
42
 
 
43
    wk = WheelKeys().load()
 
44
 
 
45
    keypair = ed25519ll.crypto_sign_keypair()
 
46
    vk = native(urlsafe_b64encode(keypair.vk))
 
47
    sk = native(urlsafe_b64encode(keypair.sk))
 
48
    kr = keyring.get_keyring()
 
49
    kr.set_password("wheel", vk, sk)
 
50
    sys.stdout.write("Created Ed25519 keypair with vk={0}\n".format(vk))
 
51
    sys.stdout.write("in {0!r}\n".format(kr))
 
52
 
 
53
    sk2 = kr.get_password('wheel', vk)
 
54
    if sk2 != sk:
 
55
        raise WheelError("Keyring is broken. Could not retrieve secret key.")
 
56
 
 
57
    sys.stdout.write("Trusting {0} to sign and verify all packages.\n".format(vk))
 
58
    wk.add_signer('+', vk)
 
59
    wk.trust('+', vk)
 
60
    wk.save()
 
61
 
 
62
def sign(wheelfile, replace=False, get_keyring=get_keyring):
 
63
    """Sign a wheel"""
 
64
    WheelKeys, keyring = get_keyring()
 
65
 
 
66
    ed25519ll = signatures.get_ed25519ll()
 
67
 
 
68
    wf = WheelFile(wheelfile, append=True)
 
69
    wk = WheelKeys().load()
 
70
 
 
71
    name = wf.parsed_filename.group('name')
 
72
    sign_with = wk.signers(name)[0]
 
73
    sys.stdout.write("Signing {0} with {1}\n".format(name, sign_with[1]))
 
74
 
 
75
    vk = sign_with[1]
 
76
    kr = keyring.get_keyring()
 
77
    sk = kr.get_password('wheel', vk)
 
78
    keypair = ed25519ll.Keypair(urlsafe_b64decode(binary(vk)),
 
79
                                urlsafe_b64decode(binary(sk)))
 
80
 
 
81
 
 
82
    record_name = wf.distinfo_name + '/RECORD'
 
83
    sig_name = wf.distinfo_name + '/RECORD.jws'
 
84
    if sig_name in wf.zipfile.namelist():
 
85
        raise WheelError("Wheel is already signed.")
 
86
    record_data = wf.zipfile.read(record_name)
 
87
    payload = {"hash":"sha256=" + native(urlsafe_b64encode(hashlib.sha256(record_data).digest()))}
 
88
    sig = signatures.sign(payload, keypair)
 
89
    wf.zipfile.writestr(sig_name, json.dumps(sig, sort_keys=True))
 
90
    wf.zipfile.close()
 
91
 
 
92
def unsign(wheelfile):
 
93
    """
 
94
    Remove RECORD.jws from a wheel by truncating the zip file.
 
95
 
 
96
    RECORD.jws must be at the end of the archive. The zip file must be an
 
97
    ordinary archive, with the compressed files and the directory in the same
 
98
    order, and without any non-zip content after the truncation point.
 
99
    """
 
100
    vzf = VerifyingZipFile(wheelfile, "a")
 
101
    info = vzf.infolist()
 
102
    if not (len(info) and info[-1].filename.endswith('/RECORD.jws')):
 
103
        raise WheelError("RECORD.jws not found at end of archive.")
 
104
    vzf.pop()
 
105
    vzf.close()
 
106
 
 
107
def verify(wheelfile):
 
108
    """Verify a wheel.
 
109
 
 
110
    The signature will be verified for internal consistency ONLY and printed.
 
111
    Wheel's own unpack/install commands verify the manifest against the
 
112
    signature and file contents.
 
113
    """
 
114
    wf = WheelFile(wheelfile)
 
115
    sig_name = wf.distinfo_name + '/RECORD.jws'
 
116
    sig = json.loads(native(wf.zipfile.open(sig_name).read()))
 
117
    verified = signatures.verify(sig)
 
118
    sys.stderr.write("Signatures are internally consistent.\n")
 
119
    sys.stdout.write(json.dumps(verified, indent=2))
 
120
    sys.stdout.write('\n')
 
121
 
 
122
def unpack(wheelfile, dest='.'):
 
123
    """Unpack a wheel.
 
124
 
 
125
    Wheel content will be unpacked to {dest}/{name}-{ver}, where {name}
 
126
    is the package name and {ver} its version.
 
127
 
 
128
    :param wheelfile: The path to the wheel.
 
129
    :param dest: Destination directory (default to current directory).
 
130
    """
 
131
    wf = WheelFile(wheelfile)
 
132
    namever = wf.parsed_filename.group('namever')
 
133
    destination = os.path.join(dest, namever)
 
134
    sys.stderr.write("Unpacking to: %s\n" % (destination))
 
135
    wf.zipfile.extractall(destination)
 
136
    wf.zipfile.close()
 
137
 
 
138
def install(requirements, requirements_file=None,
 
139
            wheel_dirs=None, force=False, list_files=False,
 
140
            dry_run=False):
 
141
    """Install wheels.
 
142
 
 
143
    :param requirements: A list of requirements or wheel files to install.
 
144
    :param requirements_file: A file containing requirements to install.
 
145
    :param wheel_dirs: A list of directories to search for wheels.
 
146
    :param force: Install a wheel file even if it is not compatible.
 
147
    :param list_files: Only list the files to install, don't install them.
 
148
    :param dry_run: Do everything but the actual install.
 
149
    """
 
150
 
 
151
    # If no wheel directories specified, use the WHEELPATH environment
 
152
    # variable, or the current directory if that is not set.
 
153
    if not wheel_dirs:
 
154
        wheelpath = os.getenv("WHEELPATH")
 
155
        if wheelpath:
 
156
            wheel_dirs = wheelpath.split(os.pathsep)
 
157
        else:
 
158
            wheel_dirs = [ os.path.curdir ]
 
159
 
 
160
    # Get a list of all valid wheels in wheel_dirs
 
161
    all_wheels = []
 
162
    for d in wheel_dirs:
 
163
        for w in os.listdir(d):
 
164
            if w.endswith('.whl'):
 
165
                wf = WheelFile(os.path.join(d, w))
 
166
                if wf.compatible:
 
167
                    all_wheels.append(wf)
 
168
 
 
169
    # If there is a requirements file, add it to the list of requirements
 
170
    if requirements_file:
 
171
        # If the file doesn't exist, search for it in wheel_dirs
 
172
        # This allows standard requirements files to be stored with the
 
173
        # wheels.
 
174
        if not os.path.exists(requirements_file):
 
175
            for d in wheel_dirs:
 
176
                name = os.path.join(d, requirements_file)
 
177
                if os.path.exists(name):
 
178
                    requirements_file = name
 
179
                    break
 
180
 
 
181
        with open(requirements_file) as fd:
 
182
            requirements.extend(fd)
 
183
 
 
184
    to_install = []
 
185
    for req in requirements:
 
186
        if req.endswith('.whl'):
 
187
            # Explicitly specified wheel filename
 
188
            if os.path.exists(req):
 
189
                wf = WheelFile(req)
 
190
                if wf.compatible or force:
 
191
                    to_install.append(wf)
 
192
                else:
 
193
                    msg = ("{0} is not compatible with this Python. "
 
194
                           "--force to install anyway.".format(req))
 
195
                    raise WheelError(msg)
 
196
            else:
 
197
                # We could search on wheel_dirs, but it's probably OK to
 
198
                # assume the user has made an error.
 
199
                raise WheelError("No such wheel file: {}".format(req))
 
200
            continue
 
201
 
 
202
        # We have a requirement spec
 
203
        # If we don't have pkg_resources, this will raise an exception
 
204
        matches = matches_requirement(req, all_wheels)
 
205
        if not matches:
 
206
            raise WheelError("No match for requirement {}".format(req))
 
207
        to_install.append(max(matches))
 
208
 
 
209
    # We now have a list of wheels to install
 
210
    if list_files:
 
211
        sys.stdout.write("Installing:\n")
 
212
 
 
213
    if dry_run:
 
214
        return
 
215
 
 
216
    for wf in to_install:
 
217
        if list_files:
 
218
            sys.stdout.write("    {0}\n".format(wf.filename))
 
219
            continue
 
220
        wf.install(force=force)
 
221
        wf.zipfile.close()
 
222
 
 
223
def install_scripts(distributions):
 
224
    """
 
225
    Regenerate the entry_points console_scripts for the named distribution.
 
226
    """
 
227
    try:
 
228
        from setuptools.command import easy_install
 
229
        import pkg_resources
 
230
    except ImportError:
 
231
        raise RuntimeError("'wheel install_scripts' needs setuptools.")
 
232
 
 
233
    for dist in distributions:
 
234
        pkg_resources_dist = pkg_resources.get_distribution(dist)
 
235
        install = get_install_command(dist)
 
236
        command = easy_install.easy_install(install.distribution)
 
237
        command.args = ['wheel'] # dummy argument
 
238
        command.finalize_options()
 
239
        command.install_egg_scripts(pkg_resources_dist)
 
240
 
 
241
def convert(installers, dest_dir, verbose):
 
242
    require_pkgresources('wheel convert')
 
243
 
 
244
    # Only support wheel convert if pkg_resources is present
 
245
    from ..wininst2wheel import bdist_wininst2wheel
 
246
    from ..egg2wheel import egg2wheel
 
247
 
 
248
    for pat in installers:
 
249
        for installer in iglob(pat):
 
250
            if os.path.splitext(installer)[1] == '.egg':
 
251
                conv = egg2wheel
 
252
            else:
 
253
                conv = bdist_wininst2wheel
 
254
            if verbose:
 
255
                sys.stdout.write("{0}... ".format(installer))
 
256
                sys.stdout.flush()
 
257
            conv(installer, dest_dir)
 
258
            if verbose:
 
259
                sys.stdout.write("OK\n")
 
260
 
 
261
def parser():
 
262
    p = argparse.ArgumentParser()
 
263
    s = p.add_subparsers(help="commands")
 
264
 
 
265
    def keygen_f(args):
 
266
        keygen()
 
267
    keygen_parser = s.add_parser('keygen', help='Generate signing key')
 
268
    keygen_parser.set_defaults(func=keygen_f)
 
269
 
 
270
    def sign_f(args):
 
271
        sign(args.wheelfile)
 
272
    sign_parser = s.add_parser('sign', help='Sign wheel')
 
273
    sign_parser.add_argument('wheelfile', help='Wheel file')
 
274
    sign_parser.set_defaults(func=sign_f)
 
275
 
 
276
    def unsign_f(args):
 
277
        unsign(args.wheelfile)
 
278
    unsign_parser = s.add_parser('unsign', help=unsign.__doc__)
 
279
    unsign_parser.add_argument('wheelfile', help='Wheel file')
 
280
    unsign_parser.set_defaults(func=unsign_f)
 
281
 
 
282
    def verify_f(args):
 
283
        verify(args.wheelfile)
 
284
    verify_parser = s.add_parser('verify', help=verify.__doc__)
 
285
    verify_parser.add_argument('wheelfile', help='Wheel file')
 
286
    verify_parser.set_defaults(func=verify_f)
 
287
 
 
288
    def unpack_f(args):
 
289
        unpack(args.wheelfile, args.dest)
 
290
    unpack_parser = s.add_parser('unpack', help='Unpack wheel')
 
291
    unpack_parser.add_argument('--dest', '-d', help='Destination directory',
 
292
                               default='.')
 
293
    unpack_parser.add_argument('wheelfile', help='Wheel file')
 
294
    unpack_parser.set_defaults(func=unpack_f)
 
295
 
 
296
    def install_f(args):
 
297
        install(args.requirements, args.requirements_file,
 
298
                args.wheel_dirs, args.force, args.list_files)
 
299
    install_parser = s.add_parser('install', help='Install wheels')
 
300
    install_parser.add_argument('requirements', nargs='*',
 
301
                                help='Requirements to install.')
 
302
    install_parser.add_argument('--force', default=False,
 
303
                                action='store_true',
 
304
                                help='Install incompatible wheel files.')
 
305
    install_parser.add_argument('--wheel-dir', '-d', action='append',
 
306
                                dest='wheel_dirs',
 
307
                                help='Directories containing wheels.')
 
308
    install_parser.add_argument('--requirements-file', '-r',
 
309
                                help="A file containing requirements to "
 
310
                                "install.")
 
311
    install_parser.add_argument('--list', '-l', default=False,
 
312
                                dest='list_files',
 
313
                                action='store_true',
 
314
                                help="List wheels which would be installed, "
 
315
                                "but don't actually install anything.")
 
316
    install_parser.set_defaults(func=install_f)
 
317
 
 
318
    def install_scripts_f(args):
 
319
        install_scripts(args.distributions)
 
320
    install_scripts_parser = s.add_parser('install-scripts', help='Install console_scripts')
 
321
    install_scripts_parser.add_argument('distributions', nargs='*',
 
322
                                        help='Regenerate console_scripts for these distributions')
 
323
    install_scripts_parser.set_defaults(func=install_scripts_f)
 
324
 
 
325
    def convert_f(args):
 
326
        convert(args.installers, args.dest_dir, args.verbose)
 
327
    convert_parser = s.add_parser('convert', help='Convert egg or wininst to wheel')
 
328
    convert_parser.add_argument('installers', nargs='*', help='Installers to convert')
 
329
    convert_parser.add_argument('--dest-dir', '-d', default=os.path.curdir,
 
330
            help="Directory to store wheels (default %(default)s)")
 
331
    convert_parser.add_argument('--verbose', '-v', action='store_true')
 
332
    convert_parser.set_defaults(func=convert_f)
 
333
 
 
334
    def version_f(args):
 
335
        from .. import __version__
 
336
        sys.stdout.write("wheel %s\n" % __version__)
 
337
    version_parser = s.add_parser('version', help='Print version and exit')
 
338
    version_parser.set_defaults(func=version_f)
 
339
 
 
340
    def help_f(args):
 
341
        p.print_help()
 
342
    help_parser = s.add_parser('help', help='Show this help')
 
343
    help_parser.set_defaults(func=help_f)
 
344
 
 
345
    return p
 
346
 
 
347
def main():
 
348
    p = parser()
 
349
    args = p.parse_args()
 
350
    if not hasattr(args, 'func'):
 
351
        p.print_help()
 
352
    else:
 
353
        # XXX on Python 3.3 we get 'args has no func' rather than short help.
 
354
        try:
 
355
            args.func(args)
 
356
            return 0
 
357
        except WheelError as e:
 
358
            sys.stderr.write(e.message + "\n")
 
359
    return 1