Example #1
0
 def remove_aka(self, channel, name):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     db = self.get_db(channel)
     db.cursor().execute('DELETE FROM aliases WHERE name = ?', (name,))
     db.commit()
Example #2
0
 def remove_aka(self, channel, name):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     db = self.get_db(channel)
     db.query(SQLAlchemyAlias).filter(SQLAlchemyAlias.name == name).delete()
     db.commit()
Example #3
0
 def addAlias(self, irc, name, alias, lock=False):
     if self._invalidCharsRe.search(name):
         raise AliasError, 'Names cannot contain spaces or square brackets.'
     if '|' in name:
         raise AliasError, 'Names cannot contain pipes.'
     realName = callbacks.canonicalName(name)
     if name != realName:
         s = format('That name isn\'t valid.  Try %q instead.', realName)
         raise AliasError, s
     name = realName
     if self.isCommandMethod(name):
         if realName not in self.aliases:
             s = 'You can\'t overwrite commands in this plugin.'
             raise AliasError, s
     if name in self.aliases:
         (currentAlias, locked, _) = self.aliases[name]
         if locked and currentAlias != alias:
             raise AliasError, format('Alias %q is locked.', name)
     try:
         f = makeNewAlias(name, alias)
         f = new.instancemethod(f, self, Alias)
     except RecursiveAlias:
         raise AliasError, 'You can\'t define a recursive alias.'
     aliasGroup = self.registryValue('aliases', value=False)
     if name in self.aliases:
         # We gotta remove it so its value gets updated.
         aliasGroup.unregister(name)
     conf.registerGlobalValue(aliasGroup, name, registry.String(alias, ''))
     conf.registerGlobalValue(aliasGroup.get(name), 'locked',
                              registry.Boolean(lock, ''))
     self.aliases[name] = [alias, lock, f]
Example #4
0
def get_feedName(irc, msg, args, state):
    if ircutils.isChannel(args[0]):
        state.errorInvalid('feed name', args[0], 'must not be channel names.')
    if not registry.isValidRegistryName(args[0]):
        state.errorInvalid('feed name', args[0],
                           'Feed names must not include spaces.')
    state.args.append(callbacks.canonicalName(args.pop(0)))
Example #5
0
 def addAlias(self, irc, name, alias, lock=False):
     if not self.isValidName(name):
         raise AliasError('Invalid alias name.')
     realName = callbacks.canonicalName(name)
     if name != realName:
         s = format(_('That name isn\'t valid.  Try %q instead.'), realName)
         raise AliasError(s)
     name = realName
     if self.isCommandMethod(name):
         if realName not in self.aliases:
             s = 'You can\'t overwrite commands in this plugin.'
             raise AliasError(s)
     if name in self.aliases:
         (currentAlias, locked, _) = self.aliases[name]
         if locked and currentAlias != alias:
             raise AliasError(format('Alias %q is locked.', name))
     f = makeNewAlias(name, alias)
     f = types.MethodType(f, self)
     if name in self.aliases:
         # We gotta remove it so its value gets updated.
         self.aliasRegistryRemove(name)
     aliasGroup = self.aliasRegistryGroup(name)
     if needsEscaping(name):
         confname = escapeAlias(name)
     else:
         confname = name
     conf.registerGlobalValue(aliasGroup, confname,
                              registry.String(alias, ''))
     conf.registerGlobalValue(aliasGroup.get(confname), 'locked',
                              registry.Boolean(lock, ''))
     self.aliases[name] = [alias, lock, f]
Example #6
0
 def addAlias(self, irc, name, alias, lock=False):
     if self._invalidCharsRe.search(name):
         raise AliasError, "Names cannot contain spaces or square brackets."
     if "|" in name:
         raise AliasError, "Names cannot contain pipes."
     realName = callbacks.canonicalName(name)
     if name != realName:
         s = format("That name isn't valid.  Try %q instead.", realName)
         raise AliasError, s
     name = realName
     if self.isCommandMethod(name):
         if realName not in self.aliases:
             s = "You can't overwrite commands in this plugin."
             raise AliasError, s
     if name in self.aliases:
         (currentAlias, locked, _) = self.aliases[name]
         if locked and currentAlias != alias:
             raise AliasError, format("Alias %q is locked.", name)
     try:
         f = makeNewAlias(name, alias)
         f = new.instancemethod(f, self, Alias)
     except RecursiveAlias:
         raise AliasError, "You can't define a recursive alias."
     if name in self.aliases:
         # We gotta remove it so its value gets updated.
         conf.supybot.plugins.Alias.aliases.unregister(name)
     conf.supybot.plugins.Alias.aliases.register(name, registry.String(alias, ""))
     conf.supybot.plugins.Alias.aliases.get(name).register("locked", registry.Boolean(lock, ""))
     self.aliases[name] = [alias, lock, f]
Example #7
0
 def addAlias(self, irc, name, alias, lock=False):
     if not self._validNameRe.search(name):
         raise AliasError('Names can only contain alphanumerical '
                 'characters, dots, pipes, and '
                 'exclamation/interrogatin marks '
                 '(and the first character cannot be a number).')
     realName = callbacks.canonicalName(name)
     if name != realName:
         s = format(_('That name isn\'t valid.  Try %q instead.'), realName)
         raise AliasError(s)
     name = realName
     if self.isCommandMethod(name):
         if realName not in self.aliases:
             s = 'You can\'t overwrite commands in this plugin.'
             raise AliasError(s)
     if name in self.aliases:
         (currentAlias, locked, _) = self.aliases[name]
         if locked and currentAlias != alias:
             raise AliasError(format('Alias %q is locked.', name))
     f = makeNewAlias(name, alias)
     f = types.MethodType(f, self)
     if '.' in name or '|' in name:
         aliasGroup = self.registryValue('escapedaliases', value=False)
         confname = escapeAlias(name)
     else:
         aliasGroup = self.registryValue('aliases', value=False)
         confname = name
     if name in self.aliases:
         # We gotta remove it so its value gets updated.
         aliasGroup.unregister(confname)
     conf.registerGlobalValue(aliasGroup, confname,
                              registry.String(alias, ''))
     conf.registerGlobalValue(aliasGroup.get(confname), 'locked',
                              registry.Boolean(lock, ''))
     self.aliases[name] = [alias, lock, f]
Example #8
0
def renameCommand(cb, name, newName):
    assert not hasattr(cb, newName), "Cannot rename over existing attributes."
    assert newName == callbacks.canonicalName(newName), "newName must already be normalized."
    if name != newName:
        method = getattr(cb.__class__, name)
        setattr(cb.__class__, newName, method)
        delattr(cb.__class__, name)
Example #9
0
 def __call__(self, irc, msg):
     self.__parent.__call__(irc, msg)
     irc = callbacks.SimpleProxy(irc, msg)
     newFeeds = {}
     for channel in irc.state.channels:
         feeds = self.registryValue("announce", channel)
         for name in feeds:
             commandName = callbacks.canonicalName(name)
             if self.isCommandMethod(commandName):
                 url = self.feedNames[commandName][0]
             else:
                 url = name
             if self.willGetNewFeed(url):
                 newFeeds.setdefault((url, name), []).append(channel)
     for ((url, name), channels) in newFeeds.iteritems():
         # We check if we can acquire the lock right here because if we
         # don't, we'll possibly end up spawning a lot of threads to get
         # the feed, because this thread may run for a number of bytecodes
         # before it switches to a thread that'll get the lock in
         # _newHeadlines.
         if self.acquireLock(url, blocking=False):
             try:
                 t = threading.Thread(
                     target=self._newHeadlines, name=format("Fetching %u", url), args=(irc, channels, name, url)
                 )
                 self.log.info("Checking for announcements at %u", url)
                 world.threadsSpawned += 1
                 t.setDaemon(True)
                 t.start()
             finally:
                 self.releaseLock(url)
                 time.sleep(0.1)  # So other threads can run.
Example #10
0
 def has_aka(self, channel, name):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     count = self.get_db(channel).query(SQLAlchemyAlias) \
             .filter(SQLAlchemyAlias.name == name) \
             .count()
     return bool(count)
Example #11
0
 def has_aka(self, channel, name):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     db = self.get_db(channel)
     return self.get_db(channel).cursor() \
             .execute("""SELECT COUNT() as count
                         FROM aliases WHERE name = ?;""", (name,)) \
             .fetchone()[0]
Example #12
0
 def get_alias(self, channel, name):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     try:
         return self.get_db(channel).query(SQLAlchemyAlias.alias) \
                 .filter(SQLAlchemyAlias.name == name).one()[0]
     except sqlalchemy.orm.exc.NoResultFound:
         return None
 def testCanonicalName(self):
     self.assertEqual('foo', callbacks.canonicalName('foo'))
     self.assertEqual('foobar', callbacks.canonicalName('foo-bar'))
     self.assertEqual('foobar', callbacks.canonicalName('foo_bar'))
     self.assertEqual('foobar', callbacks.canonicalName('FOO-bar'))
     self.assertEqual('foobar', callbacks.canonicalName('FOOBAR'))
     self.assertEqual('foobar', callbacks.canonicalName('foo___bar'))
     self.assertEqual('foobar', callbacks.canonicalName('_f_o_o-b_a_r'))
     # The following seems to be a hack for the Karma plugin; I'm not
     # entirely sure that it's completely necessary anymore.
     self.assertEqual('foobar--', callbacks.canonicalName('foobar--'))
Example #14
0
 def get_aka_lock(self, channel, name):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     try:
         return self.get_db(channel) \
                 .query(SQLAlchemyAlias.locked, SQLAlchemyAlias.locked_by, SQLAlchemyAlias.locked_at)\
                 .filter(SQLAlchemyAlias.name == name).one()
     except sqlalchemy.orm.exc.NoResultFound:
         raise AkaError(_('This Aka does not exist.'))
Example #15
0
 def removeAlias(self, name, evenIfLocked=False):
     name = callbacks.canonicalName(name)
     if name in self.aliases and self.isCommandMethod(name):
         if evenIfLocked or not self.aliases[name][1]:
             del self.aliases[name]
             conf.supybot.plugins.Alias.aliases.unregister(name)
         else:
             raise AliasError, 'That alias is locked.'
     else:
         raise AliasError, 'There is no such alias.'
Example #16
0
 def removeAlias(self, name, evenIfLocked=False):
     name = callbacks.canonicalName(name)
     if name in self.aliases and self.isCommandMethod(name):
         if evenIfLocked or not self.aliases[name][1]:
             del self.aliases[name]
             self.aliasRegistryRemove(name)
         else:
             raise AliasError('That alias is locked.')
     else:
         raise AliasError('There is no such alias.')
Example #17
0
 def unlock_aka(self, channel, name, by):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     db = self.get_db(channel)
     cursor = db.cursor()
     cursor.execute("""UPDATE aliases SET locked=0, locked_at=?
                       WHERE name = ?""", (datetime.datetime.now(), name))
     if cursor.rowcount == 0:
         raise AkaError(_('This Aka does not exist.'))
     db.commit()
Example #18
0
 def add_aka(self, channel, name, alias):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if self.has_aka(channel, name):
         raise AkaError(_('This Aka already exists.'))
     if sys.version_info[0] < 3:
         if isinstance(name, str):
             name = name.decode('utf8')
         if isinstance(alias, str):
             alias = alias.decode('utf8')
     db = self.get_db(channel)
     db.add(SQLAlchemyAlias(name, alias))
     db.commit()
Example #19
0
 def get_aka_lock(self, channel, name):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     cursor = self.get_db(channel).cursor()
     cursor.execute("""SELECT locked, locked_by, locked_at
                       FROM aliases WHERE name = ?;""", (name,))
     r = cursor.fetchone()
     if r:
         return (bool(r[0]), r[1], r[2])
     else:
         raise AkaError(_('This Aka does not exist.'))
Example #20
0
    def search(self, irc, msg, args, optlist, query):
        """[--channel <#channel>] <query>

        Searches Akas defined for <channel>. If <channel> is not specified,
        searches all global Akas."""
        query = callbacks.canonicalName(query, preserve_spaces=True)
        channel = 'global'
        for (option, arg) in optlist:
            if option == 'channel':
                if not ircutils.isChannel(arg):
                    irc.error(_('%r is not a valid channel.') % arg,
                            Raise=True)
                channel = arg
        aka_list = self._db.get_aka_list(channel)
        aka_list = [callbacks.canonicalName(k[0], preserve_spaces=True)
                    for k in aka_list]
        matching = [aka for aka in aka_list if query in aka]
        if matching:
            irc.replies(matching)
        else:
            irc.error(_("No matching Akas were found."))
Example #21
0
 def TestDocumentation(self):
     if self.__class__ in (PluginTestCase, ChannelPluginTestCase):
         return
     for cb in self.irc.callbacks:
         name = cb.name()
         if (name in self._noTestDoc) and not name.lower() in self.__class__.__name__.lower():
             continue
         self.failUnless(sys.modules[cb.__class__.__name__].__doc__, "%s has no module documentation." % name)
         if hasattr(cb, "isCommandMethod"):
             for attr in dir(cb):
                 if cb.isCommandMethod(attr) and attr == callbacks.canonicalName(attr):
                     self.failUnless(getattr(cb, attr, None).__doc__, "%s.%s has no help." % (name, attr))
Example #22
0
 def get_alias(self, channel, name):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     cursor = self.get_db(channel).cursor()
     cursor.execute("""SELECT alias FROM aliases
                       WHERE name = ?;""", (name,))
     r = cursor.fetchone()
     if r:
         return r[0]
     else:
         return None
Example #23
0
 def isCommandMethod(self, name):
     args = name.split(' ')
     if len(args) > 1 and \
             callbacks.canonicalName(args[0]) != self.canonicalName():
         for cb in dynamic.irc.callbacks: # including this plugin
             if cb.getCommand(args[0:-1]):
                 return False
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     channel = dynamic.channel or 'global'
     return self._db.has_aka(channel, name) or \
             self._db.has_aka('global', name) or \
             self.__parent.isCommandMethod(name)
Example #24
0
 def add_aka(self, channel, name, alias):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if self.has_aka(channel, name):
         raise AkaError(_('This Aka already exists.'))
     if minisix.PY2:
         if isinstance(name, str):
             name = name.decode('utf8')
         if isinstance(alias, str):
             alias = alias.decode('utf8')
     db = self.get_db(channel)
     cursor = db.cursor()
     cursor.execute("""INSERT INTO aliases VALUES (
         NULL, ?, ?, 0, NULL, NULL);""", (name, alias))
     db.commit()
Example #25
0
    def search(self, irc, msg, args, optlist, query):
        """[--channel <#channel>] <query>

        Searches Akas defined for <channel>. If <channel> is not specified,
        searches all global Akas."""
        query = callbacks.canonicalName(query, preserve_spaces=True)
        channel = 'global'
        for (option, arg) in optlist:
            if option == 'channel':
                if not ircutils.isChannel(arg):
                    irc.error(_('%r is not a valid channel.') % arg,
                              Raise=True)
                channel = arg
        aka_list = self._db.get_aka_list(channel)
        aka_list = [
            callbacks.canonicalName(k[0], preserve_spaces=True)
            for k in aka_list
        ]
        matching = [aka for aka in aka_list if query in aka]
        if matching:
            irc.replies(matching)
        else:
            irc.error(_("No matching Akas were found."))
Example #26
0
 def removeAlias(self, name, evenIfLocked=False):
     name = callbacks.canonicalName(name)
     if name in self.aliases and self.isCommandMethod(name):
         if evenIfLocked or not self.aliases[name][1]:
             del self.aliases[name]
             if '.' in name or '|' in name:
                 conf.supybot.plugins.Alias.escapedaliases.unregister(
                     escapeAlias(name))
             else:
                 conf.supybot.plugins.Alias.aliases.unregister(name)
         else:
             raise AliasError('That alias is locked.')
     else:
         raise AliasError('There is no such alias.')
Example #27
0
 def add_aka(self, channel, name, alias):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if self.has_aka(channel, name):
         raise AkaError(_('This Aka already exists.'))
     if sys.version_info[0] < 3:
         if isinstance(name, str):
             name = name.decode('utf8')
         if isinstance(alias, str):
             alias = alias.decode('utf8')
     db = self.get_db(channel)
     cursor = db.cursor()
     cursor.execute("""INSERT INTO aliases VALUES (
         NULL, ?, ?, 0, NULL, NULL);""", (name, alias))
     db.commit()
Example #28
0
 def isCommandMethod(self, name):
     args = name.split(' ')
     if '|' in args:
         return False
     if len(args) > 1 and \
             callbacks.canonicalName(args[0]) != self.canonicalName():
         for cb in dynamic.irc.callbacks: # including this plugin
             if cb.isCommandMethod(' '.join(args[0:-1])):
                 return False
     if minisix.PY2 and isinstance(name, str):
         name = name.decode('utf8')
     channel = dynamic.channel or 'global'
     return self._db.has_aka(channel, name) or \
             self._db.has_aka('global', name) or \
             self.__parent.isCommandMethod(name)
Example #29
0
 def testDocumentation(self):
     if self.__class__ in (PluginTestCase, ChannelPluginTestCase):
         return
     for cb in self.irc.callbacks:
         name = cb.name()
         if ((name in self._noTestDoc) and \
            not name.lower() in self.__class__.__name__.lower()):
             continue
         self.failUnless(sys.modules[cb.__class__.__name__].__doc__,
                         '%s has no module documentation.' % name)
         if hasattr(cb, 'isCommandMethod'):
             for attr in dir(cb):
                 if cb.isCommandMethod(attr) and \
                    attr == callbacks.canonicalName(attr):
                     self.failUnless(getattr(cb, attr, None).__doc__,
                                     '%s.%s has no help.' % (name, attr))
Example #30
0
 def unlock_aka(self, channel, name, by):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if minisix.PY2 and isinstance(name, str):
         name = name.decode('utf8')
     db = self.get_db(channel)
     try:
         aka = db.query(SQLAlchemyAlias) \
                 .filter(SQLAlchemyAlias.name == name).one()
     except sqlalchemy.orm.exc.NoResultFound:
         raise AkaError(_('This Aka does not exist.'))
     if not aka.locked:
         raise AkaError(_('This Aka is already unlocked.'))
     aka.locked = False
     aka.locked_by = by
     aka.locked_at = datetime.datetime.now()
     db.commit()
Example #31
0
File: plugin.py Project: totte/aide
 def lock_aka(self, channel, name, by):
     name = callbacks.canonicalName(name)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     db = self.get_db(channel)
     try:
         aka = db.query(Alias) \
                 .filter(Alias.name == name).one()
     except sqlalchemy.orm.exc.NoResultFound:
         raise AkaError(_('This Aka does not exist'))
     if aka.locked:
         raise AkaError(_('This Aka is already locked.'))
     aka.locked = True
     aka.locked_by = by
     aka.locked_at = datetime.datetime.now()
     db.commit()
Example #32
0
 def unlock_aka(self, channel, name, by):
     name = callbacks.canonicalName(name, preserve_spaces=True)
     if sys.version_info[0] < 3 and isinstance(name, str):
         name = name.decode('utf8')
     db = self.get_db(channel)
     try:
         aka = db.query(SQLAlchemyAlias) \
                 .filter(SQLAlchemyAlias.name == name).one()
     except sqlalchemy.orm.exc.NoResultFound:
         raise AkaError(_('This Aka does not exist.'))
     if not aka.locked:
         raise AkaError(_('This Aka is already unlocked.'))
     aka.locked = False
     aka.locked_by = by
     aka.locked_at = datetime.datetime.now()
     db.commit()
Example #33
0
 def addAlias(self, irc, name, alias, lock=False):
     if not self._validNameRe.search(name):
         raise AliasError('Names can only contain alphanumerical '
                          'characters, dots, pipes, and '
                          'exclamation/interrogatin marks '
                          '(and the first character cannot be a number).')
     realName = callbacks.canonicalName(name)
     if name != realName:
         s = format(_('That name isn\'t valid.  Try %q instead.'), realName)
         raise AliasError(s)
     name = realName
     if self.isCommandMethod(name):
         if realName not in self.aliases:
             s = 'You can\'t overwrite commands in this plugin.'
             raise AliasError(s)
     if name in self.aliases:
         (currentAlias, locked, _) = self.aliases[name]
         if locked and currentAlias != alias:
             raise AliasError(format('Alias %q is locked.', name))
     try:
         f = makeNewAlias(name, alias)
         f = types.MethodType(f, self)
     except RecursiveAlias:
         raise AliasError('You can\'t define a recursive alias.')
     if '.' in name or '|' in name:
         aliasGroup = self.registryValue('escapedaliases', value=False)
         confname = escapeAlias(name)
     else:
         aliasGroup = self.registryValue('aliases', value=False)
         confname = name
     if name in self.aliases:
         # We gotta remove it so its value gets updated.
         aliasGroup.unregister(confname)
     conf.registerGlobalValue(aliasGroup, confname,
                              registry.String(alias, ''))
     conf.registerGlobalValue(aliasGroup.get(confname), 'locked',
                              registry.Boolean(lock, ''))
     self.aliases[name] = [alias, lock, f]
Example #34
0
def getCommandName(irc, msg, args, state):
    if ' ' in args[0]:
        state.errorInvalid(_('command name'), args[0])
    else:
        state.args.append(callbacks.canonicalName(args.pop(0)))
Example #35
0
def registerDefaultPlugin(command, plugin):
    command = callbacks.canonicalName(command)
    conf.registerGlobalValue(conf.supybot.commands.defaultPlugins,
                             command, registry.String(plugin, ''))
    # This must be set, or the quotes won't be removed.
    conf.supybot.commands.defaultPlugins.get(command).set(plugin)
def get_status_uri(irc, msg, args, state):
    if not utils.web.urlRe.match(args[0]) and not os.path.exists(args[0]):
        state.errorInvalid('status uri', args[0],
                           'Status URIs must be valid URLs or file names.')
    state.args.append(callbacks.canonicalName(args.pop(0)))
Example #37
0
def getEventName(irc, msg, args, state):
    if not registry.isValidRegistryName(args[0]):
        state.errorInvalid('event name', args[0],
                           'Illegal event name')
    state.args.append(callbacks.canonicalName(args.pop(0)))
Example #38
0
def getFeedName(irc, msg, args, state):
    if not registry.isValidRegistryName(args[0]):
        state.errorInvalid('feed name', args[0],
                           'Feed names must not include spaces.')
    state.args.append(callbacks.canonicalName(args.pop(0)))
Example #39
0
def registerDefaultPlugin(command, plugin):
    command = callbacks.canonicalName(command)
    conf.registerGlobalValue(conf.supybot.commands.defaultPlugins,
                             command, registry.String(plugin, ''))
    # This must be set, or the quotes won't be removed.
    conf.supybot.commands.defaultPlugins.get(command).set(plugin)
Example #40
0
def getCommandName(irc, msg, args, state):
    if ' ' in args[0]:
        state.errorInvalid(_('command name'), args[0])
    else:
        state.args.append(callbacks.canonicalName(args.pop(0)))
Example #41
0
def getFeedName(irc, msg, args, state):
    if not registry.isValidRegistryName(args[0]):
        state.errorInvalid("feed name", args[0], "Feed names must not include spaces.")
    state.args.append(callbacks.canonicalName(args.pop(0)))