def put(self, filename):
    session = gaeserver.DoMunkiAuth(require_level=gaeserver.LEVEL_UPLOADPKG)

    filename = urllib.unquote(filename)
    hash_str = self.request.get('hash')
    catalogs = self.request.get('catalogs', None)
    manifests = self.request.get('manifests', None)
    install_types = self.request.get('install_types')

    if catalogs == '':
      catalogs = []
    elif catalogs:
      catalogs = catalogs.split(',')
    if manifests == '':
      manifests = []
    elif manifests:
      manifests = manifests.split(',')
    if install_types:
      install_types = install_types.split(',')

    mpl = MunkiPackageInfoPlistStrict(self.request.body)
    try:
      mpl.Parse()
    except plist.PlistError, e:
      logging.exception('Invalid pkginfo plist PUT: \n%s\n', self.request.body)
      self.response.set_status(400)
      self.response.out.write(str(e))
      return

    lock = 'pkgsinfo_%s' % filename
    if not gae_util.ObtainLock(lock, timeout=5.0):
      self.response.set_status(403)
      self.response.out.write('Could not lock pkgsinfo')
      return

    # To avoid pkginfo uploads without corresponding packages, only allow
    # updates to existing PackageInfo entities, not creations of new ones.
    pkginfo = models.PackageInfo.get_by_key_name(filename)
    if pkginfo is None:
      logging.warning(
          'pkginfo "%s" does not exist; PUT only allows updates.', filename)
      self.response.set_status(403)
      self.response.out.write('Only updates supported')
      gae_util.ReleaseLock(lock)
      return

    # If the pkginfo is not modifiable, ensure only manifests have changed.
    if not pkginfo.IsSafeToModify():
      if not mpl.EqualIgnoringManifestsAndCatalogs(pkginfo.plist):
        logging.warning(
            'pkginfo "%s" is in stable or testing; change prohibited.',
            filename)
        self.response.set_status(403)
        self.response.out.write('Changes to pkginfo not allowed')
        gae_util.ReleaseLock(lock)
        return

    # If the update parameter asked for a careful update, by supplying
    # a hash of the last known pkgsinfo, then compare the hash to help
    # the client make a non destructive update.
    if hash_str:
      if self._Hash(pkginfo.plist) != hash_str:
        self.response.set_status(409)
        self.response.out.write('Update hash does not match')
        gae_util.ReleaseLock(lock)
        return

    # All verification has passed, so let's create the PackageInfo entity.
    pkginfo.plist = mpl
    pkginfo.name = mpl.GetPackageName()
    if catalogs is not None:
      pkginfo.catalogs = catalogs
    if manifests is not None:
      pkginfo.manifests = manifests
    if install_types:
      pkginfo.install_types = install_types
    pkginfo.put()

    gae_util.ReleaseLock(lock)

    for track in pkginfo.catalogs:
      models.Catalog.Generate(track, delay=1)

    # Log admin pkginfo put to Datastore.
    user = session.uuid
    admin_log = models.AdminPackageLog(
        user=user, action='pkginfo', filename=filename,
        catalogs=pkginfo.catalogs, manifests=pkginfo.manifests,
        install_types=pkginfo.install_types, plist=pkginfo.plist.GetXml())
    admin_log.put()
Internal implementation required to reset underlying drawing
dataset/ETHPy150Open google/simian/src/simian/mac/munki/handlers/pkgsinfo.py/PackagesInfo.put--crossover with--dataset/ETHPy150Open peterbrittain/asciimatics/asciimatics/screen.py/_AbstractCanvas._reset