docs: def sign(jar_file, cert_file, key_file, key_alias,
           extra_certs=None, digest="SHA-256", output=None):
      """
      Signs the jar (almost) identically to jarsigner.
      :exception ManifestNotFoundError, CannotFindKeyTypeError
      :return None
      """
  
      mf = Manifest()
      mf.load_from_jar(jar_file)
      mf.add_jar_entries(jar_file, digest)
  
      # create a signature manifest, and make it match the line separator
      # style of the manifest it'll be digesting.
      sf = SignatureManifest(linesep=mf.linesep)
  
      sf_digest_algorithm = "SHA-256" if digest is None else digest
      sf.digest_manifest(mf, sf_digest_algorithm)
  
      sig_digest_algorithm = digest  # No point to make it different
      sig_block_extension = private_key_type(key_file)
  
      sigdata = sf.get_signature(cert_file, key_file,
                                 extra_certs, sig_digest_algorithm)
  
      # We might just add new entries to the original JAR, but jarsigner puts
      # all META-INF/ to the beginning of the archive. Let's do the same.
      with NamedTemporaryFile() as new_jar_file:
          new_jar = ZipFile(new_jar_file, "w", ZIP_DEFLATED)
          new_jar.writestr("META-INF/MANIFEST.MF", mf.get_data())
          new_jar.writestr("META-INF/%s.SF" % key_alias, sf.get_data())
          new_jar.writestr("META-INF/%s.%s" % (key_alias, sig_block_extension),
                           sigdata)
          jar = ZipFile(jar_file, "a")
          for entry in jar.namelist():
              # TODO: In Py2, namelist() can be of type unicode
              if not entry.upper() == "META-INF/MANIFEST.MF":
                  new_jar.writestr(entry, jar.read(entry))
  
          new_jar.close()
          new_jar_file.flush()
          copyfile(new_jar_file.name, jar_file if output is None else output)