'Install a wheel to the specified paths. If kwarg ``warner`` is
specified, it should be a callable, which will be called with two
tuples indicating the wheel version of this software and the wheel
version in the file, if there is a discrepancy in the versions.
This can be used to issue any warnings to raise any exceptions.
If kwarg ``lib_only`` is True, only the purelib/platlib files are
installed, and the headers, scripts, data and dist-info metadata are
not written.
The return value is a :class:`InstalledDistribution` instance unless
``options.lib_only`` is True, in which case the return value is ``None``.'

def install(self, paths, maker, **kwargs):

    dry_run = maker.dry_run
    warner = kwargs.get(u'warner')
    lib_only = kwargs.get(u'lib_only', False)
    pathname = os.path.join(self.dirname, self.filename)
    name_ver = (u'%s-%s' % (self.name, self.version))
    data_dir = (u'%s.data' % name_ver)
    info_dir = (u'%s.dist-info' % name_ver)
    metadata_name = posixpath.join(info_dir, METADATA_FILENAME)
    wheel_metadata_name = posixpath.join(info_dir, u'WHEEL')
    record_name = posixpath.join(info_dir, u'RECORD')
    wrapper = codecs.getreader(u'utf-8')
    with ZipFile(pathname, u'r') as zf:
        with zf.open(wheel_metadata_name) as bwf:
            wf = wrapper(bwf)
            message = message_from_file(wf)
        wv = message[u'Wheel-Version'].split(u'.', 1)
        file_version = tuple([int(i) for i in wv])
        if ((file_version != self.wheel_version) and warner):
            warner(self.wheel_version, file_version)
        if (message[u'Root-Is-Purelib'] == u'true'):
            libdir = paths[u'purelib']
        else:
            libdir = paths[u'platlib']
        records = {}
        with zf.open(record_name) as bf:
            with CSVReader(stream=bf) as reader:
                for row in reader:
                    p = row[0]
                    records[p] = row
        data_pfx = posixpath.join(data_dir, u'')
        info_pfx = posixpath.join(info_dir, u'')
        script_pfx = posixpath.join(data_dir, u'scripts', u'')
        fileop = FileOperator(dry_run=dry_run)
        fileop.record = True
        bc = (not sys.dont_write_bytecode)
        outfiles = []
        workdir = tempfile.mkdtemp()
        maker.source_dir = workdir
        maker.target_dir = None
        try:
            for zinfo in zf.infolist():
                arcname = zinfo.filename
                if isinstance(arcname, text_type):
                    u_arcname = arcname
                else:
                    u_arcname = arcname.decode(u'utf-8')
                if u_arcname.endswith(u'/RECORD.jws'):
                    continue
                row = records[u_arcname]
                if (row[2] and (str(zinfo.file_size) != row[2])):
                    raise DistlibException((u'size    mismatch    for    %s' % u_arcname))
                if row[1]:
                    (kind, value) = row[1].split(u'=', 1)
                    with zf.open(arcname) as bf:
                        data = bf.read()
                    (_, digest) = self.get_hash(data, kind)
                    if (digest != value):
                        raise DistlibException((u'digest    mismatch    for    %s' % arcname))
                if (lib_only and u_arcname.startswith((info_pfx, data_pfx))):
                    logger.debug(u'lib_only:    skipping    %s', u_arcname)
                    continue
                is_script = (u_arcname.startswith(script_pfx) and (not u_arcname.endswith(u'.exe')))
                if u_arcname.startswith(data_pfx):
                    (_, where, rp) = u_arcname.split(u'/', 2)
                    outfile = os.path.join(paths[where], convert_path(rp))
                else:
                    if (u_arcname in (wheel_metadata_name, record_name)):
                        continue
                    outfile = os.path.join(libdir, convert_path(u_arcname))
                if (not is_script):
                    with zf.open(arcname) as bf:
                        fileop.copy_stream(bf, outfile)
                    outfiles.append(outfile)
                    if ((not dry_run) and row[1]):
                        with open(outfile, u'rb') as bf:
                            data = bf.read()
                            (_, newdigest) = self.get_hash(data, kind)
                            if (newdigest != digest):
                                raise DistlibException((u'digest    mismatch    on    write    for    %s' % outfile))
                    if (bc and outfile.endswith(u'.py')):
                        try:
                            pyc = fileop.byte_compile(outfile)
                            outfiles.append(pyc)
                        except Exception:
                            logger.warning(u'Byte-compilation    failed', exc_info=True)
                else:
                    fn = os.path.basename(convert_path(arcname))
                    workname = os.path.join(workdir, fn)
                    with zf.open(arcname) as bf:
                        fileop.copy_stream(bf, workname)
                    (dn, fn) = os.path.split(outfile)
                    maker.target_dir = dn
                    filenames = maker.make(fn)
                    fileop.set_executable_mode(filenames)
                    outfiles.extend(filenames)
            if lib_only:
                logger.debug(u'lib_only:    returning    None')
                dist = None
            else:
                commands = None
                file_version = self.info[u'Wheel-Version']
                if (file_version == u'1.0'):
                    ep = posixpath.join(info_dir, u'entry_points.txt')
                    try:
                        with zf.open(ep) as bwf:
                            epdata = read_exports(bwf)
                        commands = {}
                        for key in (u'console', u'gui'):
                            k = (u'%s_scripts' % key)
                            if (k in epdata):
                                commands[(u'wrap_%s' % key)] = d = {}
                                for v in epdata[k].values():
                                    s = (u'%s:%s' % (v.prefix, v.suffix))
                                    if v.flags:
                                        s += (u'    %s' % v.flags)
                                    d[v.name] = s
                    except Exception:
                        logger.warning(u'Unable    to    read    legacy    script    metadata,    so    cannot    generate    scripts')
                else:
                    try:
                        with zf.open(metadata_name) as bwf:
                            wf = wrapper(bwf)
                            commands = json.load(wf).get(u'extensions')
                            if commands:
                                commands = commands.get(u'python.commands')
                    except Exception:
                        logger.warning(u'Unable    to    read    JSON    metadata,    so    cannot    generate    scripts')
                if commands:
                    console_scripts = commands.get(u'wrap_console', {})
                    gui_scripts = commands.get(u'wrap_gui', {})
                    if (console_scripts or gui_scripts):
                        script_dir = paths.get(u'scripts', u'')
                        if (not os.path.isdir(script_dir)):
                            raise ValueError(u'Valid    script    path    not    specified')
                        maker.target_dir = script_dir
                        for (k, v) in console_scripts.items():
                            script = (u'%s    =    %s' % (k, v))
                            filenames = maker.make(script)
                            fileop.set_executable_mode(filenames)
                        if gui_scripts:
                            options = {u'gui': True}
                            for (k, v) in gui_scripts.items():
                                script = (u'%s    =    %s' % (k, v))
                                filenames = maker.make(script, options)
                                fileop.set_executable_mode(filenames)
                p = os.path.join(libdir, info_dir)
                dist = InstalledDistribution(p)
                paths = dict(paths)
                del paths[u'purelib']
                del paths[u'platlib']
                paths[u'lib'] = libdir
                p = dist.write_shared_locations(paths, dry_run)
                if p:
                    outfiles.append(p)
                dist.write_installed_files(outfiles, paths[u'prefix'], dry_run)
            return dist
        except Exception:
            logger.exception(u'installation    failed.')
            fileop.rollback()
            raise
        finally:
            shutil.rmtree(workdir)
