def update(self, modifier, dest_dir=None, **kwargs):
def get_version(path_map, info_dir):<EOL><INDENT>version = path = None<EOL>key = '<STR_LIT>' % (info_dir, METADATA_FILENAME)<EOL>if key not in path_map:<EOL><INDENT>key = '<STR_LIT>' % info_dir<EOL><DEDENT>if key in path_map:<EOL><INDENT>path = path_map[key]<EOL>version = Metadata(path=path).version<EOL><DEDENT>return version, path<EOL><DEDENT>def update_version(version, path):<EOL><INDENT>updated = None<EOL>try:<EOL><INDENT>v = NormalizedVersion(version)<EOL>i = version.find('<STR_LIT:->')<EOL>if i < <NUM_LIT:0>:<EOL><INDENT>updated = '<STR_LIT>' % version<EOL><DEDENT>else:<EOL><INDENT>parts = [int(s) for s in version[i + <NUM_LIT:1>:].split('<STR_LIT:.>')]<EOL>parts[-<NUM_LIT:1>] += <NUM_LIT:1><EOL>updated = '<STR_LIT>' % (version[:i],<EOL>'<STR_LIT:.>'.join(str(i) for i in parts))<EOL><DEDENT><DEDENT>except UnsupportedVersionError:<EOL><INDENT>logger.debug('<STR_LIT>'<EOL>'<STR_LIT>', version)<EOL><DEDENT>if updated:<EOL><INDENT>md = Metadata(path=path)<EOL>md.version = updated<EOL>legacy = not path.endswith(METADATA_FILENAME)<EOL>md.write(path=path, legacy=legacy)<EOL>logger.debug('<STR_LIT>', version,<EOL>updated)<EOL><DEDENT><DEDENT>pathname = os.path.join(self.dirname, self.filename)<EOL>name_ver = '<STR_LIT>' % (self.name, self.version)<EOL>info_dir = '<STR_LIT>' % name_ver<EOL>record_name = posixpath.join(info_dir, '<STR_LIT>')<EOL>with tempdir() as workdir:<EOL><INDENT>with ZipFile(pathname, '<STR_LIT:r>') as zf:<EOL><INDENT>path_map = {}<EOL>for zinfo in zf.infolist():<EOL><INDENT>arcname = zinfo.filename<EOL>if isinstance(arcname, text_type):<EOL><INDENT>u_arcname = arcname<EOL><DEDENT>else:<EOL><INDENT>u_arcname = arcname.decode('<STR_LIT:utf-8>')<EOL><DEDENT>if u_arcname == record_name:<EOL><INDENT>continue<EOL><DEDENT>if '<STR_LIT:..>' in u_arcname:<EOL><INDENT>raise DistlibException('<STR_LIT>'<EOL>'<STR_LIT>' % u_arcname)<EOL><DEDENT>zf.extract(zinfo, workdir)<EOL>path = os.path.join(workdir, convert_path(u_arcname))<EOL>path_map[u_arcname] = path<EOL><DEDENT><DEDENT>original_version, _ = get_version(path_map, info_dir)<EOL>modified = modifier(path_map, **kwargs)<EOL>if modified:<EOL><INDENT>current_version, path = get_version(path_map, info_dir)<EOL>if current_version and (current_version == original_version):<EOL><INDENT>update_version(current_version, path)<EOL><DEDENT>if dest_dir is None:<EOL><INDENT>fd, newpath = tempfile.mkstemp(suffix='<STR_LIT>',<EOL>prefix='<STR_LIT>',<EOL>dir=workdir)<EOL>os.close(fd)<EOL><DEDENT>else:<EOL><INDENT>if not os.path.isdir(dest_dir):<EOL><INDENT>raise DistlibException('<STR_LIT>' % dest_dir)<EOL><DEDENT>newpath = os.path.join(dest_dir, self.filename)<EOL><DEDENT>archive_paths = list(path_map.items())<EOL>distinfo = os.path.join(workdir, info_dir)<EOL>info = distinfo, info_dir<EOL>self.write_records(info, workdir, archive_paths)<EOL>self.build_zip(newpath, archive_paths)<EOL>if dest_dir is None:<EOL><INDENT>shutil.copyfile(newpath, pathname)<EOL><DEDENT><DEDENT><DEDENT>return modified<EOL>
Update the contents of a wheel in a generic way. The modifier should
be a callable which expects a dictionary argument: its keys are
archive-entry paths, and its values are absolute filesystem paths
where the contents the corresponding archive entries can be found. The
modifier is free to change the contents of the files pointed to, add
new entries and remove entries, before returning. This method will
extract the entire contents of the wheel to a temporary location, call
the modifier, and then use the passed (and possibly updated)
dictionary to write a new wheel. If ``dest_dir`` is specified, the new
wheel is written there -- otherwise, the original wheel is overwritten.

The modifier should return True if it updated the wheel, else False.
This method returns the same value the modifier returns.