def do_delegation(self, cmd, args): load_plugins() # project precondition proj_path = registry.pathfor(cmd) if proj_path is not None: os.chdir(proj_path) cmd = args[0] args = args[1:] if '-' in cmd: cmd, newargs = cmd.split('-', 1) args = [newargs, ] + args comcls = command.get(cmd) or command.get('help') try: if comcls: comobj = comcls(args) if comobj.is_relevant(): comobj._execute() else: helpcls = command.get('help') helpobj = helpcls((cmd,)) helpobj._execute() print "\n'%s %s' command not relevant here." % (cmd, ' '.join(args).strip()) else: self.do_default() except KeyboardInterrupt: print "\n" pass
def execute(self): if self.options.command: clskey = '-'.join(self.options.command) comcls = command.get(clskey) if comcls: # if args point to pin command comobj = comcls([]) parser = comobj.parser parser.print_help() if hasattr(comcls, 'get_subcommands'): subcoms = comcls.get_subcommands() if subcoms: submaxlength = len(max(subcoms.keys(), key=len)) for name, subcom in subcoms.items(): self.process_subcom(name, subcom, submaxlength) else: # ask parent command pcomcls = command.get(self.options.command[0]) if pcomcls and hasattr(pcomcls, 'get_subcommands'): subcommands = pcomcls.get_subcommands() if subcommands: for name, com in subcommands.items(): if name == self.options.command[1]: print com.__doc__ or 'Command has no docstring.' else: self.do_default_help() else: self.do_default_help()
def process_simplecom(self, name, collen): comcls = command.get(name) comobj = comcls([]) if comobj.is_relevant() or self.options.all: usage = comobj.parser.format_usage().replace("usage: ", "") doc = comcls.__doc__ or '' print "{0: >{cl}} - {1: ^24}".format(usage, doc.strip(), cl=collen)
def process_containercom(self, name, collen, subcollen): comcls = command.get(name) comobj = comcls([]) usage = comobj.parser.format_usage().replace("usage: ", "") print usage.strip() if hasattr(comcls, 'get_subcommands'): if comcls.__doc__: print "{0} {1}".format(' - ', comcls.__doc__.strip(), cl=collen) subcoms = comcls.get_subcommands() if subcoms: for name, subcom in subcoms.items(): self.process_subcom(name, subcom, subcollen)
def do_default_help(self): ''' Render pin's general help This method will iterate through all available commands that declare themselves as being 'relevant'. Some processing is done to determine formatting widths of the output and help for delegate-commands that contain subcommands are dynamically computed. ''' # print generic pin help CommandDelegator.parser.print_help() comkeys = [k for k in command.all().keys() if '-' not in k] maxlength = len(max(comkeys, key=len)) simplekeys = [] # commands without subcommands containerkeys = [] # subcommand delgates subcomkeys = [] submaxlength = maxlength # iterate over all commands for k in comkeys: # get command class comcls = command.get(k) # get dummy instance comobj = comcls([]) # check if command is relevant if comobj.is_relevant() or self.options.all: # add to specific list based on `get_subcommands' attribute if hasattr(comcls, 'get_subcommands'): containerkeys.append(k) # grab all subcommand keys subcoms = comcls.get_subcommands() if subcoms: subcomkeys += subcoms.keys() else: simplekeys.append(k) # calculate global max-length of subcommand keys if subcomkeys: submaxlength = len(max(subcomkeys, key=len)) # sort all keys simplekeys.sort() containerkeys.sort() if simplekeys or containerkeys: print "Available commands for %s:" % os.getcwd() # render simplekeys, then containerkeys for key in simplekeys: self.process_simplecom(key, maxlength) for key in containerkeys: self.process_containercom(key, maxlength, submaxlength)
def do_default_help(self): ''' Render pin's general help This method will iterate through all available commands that declare themselves as being 'relevant'. Some processing is done to determine formatting widths of the output and help for delegate-commands that contain subcommands are dynamically computed. ''' # print generic pin help CommandDelegator.parser.print_help() comkeys = [k for k in command.all().keys() if '-' not in k] maxlength = len(max(comkeys, key=len)) simplekeys = [] # commands without subcommands containerkeys = [] # subcommand delgates subcomkeys = [] submaxlength = maxlength # iterate over all commands for k in comkeys: # get command class comcls = command.get(k) # get dummy instance comobj = comcls([]) # check if command is relevant if comobj.is_relevant() or self.options.all: # add to specific list based on `get_subcommands' attribute if hasattr(comcls, 'get_subcommands'): containerkeys.append(k) # grab all subcommand keys subcoms = comcls.get_subcommands() if subcoms: subcomkeys += subcoms.keys() else: simplekeys.append(k) # calculate global max-length of subcommand keys if subcomkeys: submaxlength = len(max(subcomkeys, key=len)) # sort all keys simplekeys.sort(); containerkeys.sort() if simplekeys or containerkeys: print "Available commands for %s:" % os.getcwd() # render simplekeys, then containerkeys for key in simplekeys: self.process_simplecom(key, maxlength) for key in containerkeys: self.process_containercom(key, maxlength, submaxlength)
def compgen(): '''Do command completion for bash.''' # requires plugins to be loaded load_plugins() from pin import command, registry # get argument information nargs, args = int(sys.argv[1]), sys.argv[2:] """ The offset here is a pointer to the argument being completed. Since pin allows you to call commands against remote projects we need to adjust the completion algorithm accordingly. Each time another level of indirection is added, the offset is increased. A visual example is appropriate here. The offset starts at 1: pin ini[tab] : off=1, nargs=1 - base command pin go mypro[tab] : off=1, nargs=2 - subcommand Indirections like help cause the offset to change: pin help destr[tab] : off=2, nargs=2 - base command pin help fab deplo[tab] : off=2, nargs=3 - subcommand So now the method of the algorithm is clear. If the offset is equal to the number of arguments, we know we need to complete a base command name. If the offset is one less than the number of arguments we know to complete a subcommand. Even with a project prefix this works: pin myproj help fab deplo[tab] : off = (1 + myproj + help) = 3 nargs = 4 = subcommand! """ off = 1 proj_path = None # # # # # # # # # Project Name if args: proj_path = registry.pathfor(args[0]) # only increase the offset if we're not completing # the first argument. if nargs > 1 and proj_path is not None: # increase the offset off += 1 # change to project directory os.chdir(proj_path) # # # # # # # # # Help command if args: # complete help command if nargs == off and "help".startswith(args[-1]): return 'help' # or increase offset by 1 elif "help" in args: off += 1 # # # # # # # # # base-command if nargs == off: arg = '' # default to empty arg if len(args) == off: # set working arg to item at offset arg = args[off-1] choices = " ".join([c for c in command._commands if c.startswith(arg) and command.get(c)([]).is_relevant()]) # return the choices if there are any if choices: return choices # we want commands to complete before # project names, so if we don't return any # choices above, complete a project name now # if we're completing the first argument if nargs == 1: if proj_path is not None: return os.path.basename(proj_path) # # # # # # # # # sub-commands elif nargs == off + 1: # get our parent command com = args[off-1] # get its class comcls = command.get(com) # if it is a delegate command if hasattr(comcls, 'get_subcommands'): # get partial subcommand name if user has typed anything # or else use empty string to complete all subcom = args[off] if len(args) == off+1 else '' # get a list of the parent command's subcommands subcom_choices = comcls.get_subcommands() # if there are any subcommands if subcom_choices: # clean subcommand names (they use command-subcommand format) choices = [k.split('-')[-1] for k in subcom_choices] # return the subcommands that start with the partial subcommand name return " ".join([c for c in choices if c.startswith(subcom)]) # return nothing return ""
def compgen(): '''Do command completion for bash.''' # requires plugins to be loaded load_plugins() from pin import command, registry # get argument information nargs, args = int(sys.argv[1]), sys.argv[2:] """ The offset here is a pointer to the argument being completed. Since pin allows you to call commands against remote projects we need to adjust the completion algorithm accordingly. Each time another level of indirection is added, the offset is increased. A visual example is appropriate here. The offset starts at 1: pin ini[tab] : off=1, nargs=1 - base command pin go mypro[tab] : off=1, nargs=2 - subcommand Indirections like help cause the offset to change: pin help destr[tab] : off=2, nargs=2 - base command pin help fab deplo[tab] : off=2, nargs=3 - subcommand So now the method of the algorithm is clear. If the offset is equal to the number of arguments, we know we need to complete a base command name. If the offset is one less than the number of arguments we know to complete a subcommand. Even with a project prefix this works: pin myproj help fab deplo[tab] : off = (1 + myproj + help) = 3 nargs = 4 = subcommand! """ off = 1 proj_path = None # # # # # # # # # Project Name if args: proj_path = registry.pathfor(args[0]) # only increase the offset if we're not completing # the first argument. if nargs > 1 and proj_path is not None: # increase the offset off += 1 # change to project directory os.chdir(proj_path) # # # # # # # # # Help command if args: # complete help command if nargs == off and "help".startswith(args[-1]): return 'help' # or increase offset by 1 elif "help" in args: off += 1 # # # # # # # # # base-command if nargs == off: arg = '' # default to empty arg if len(args) == off: # set working arg to item at offset arg = args[off - 1] choices = " ".join([ c for c in command._commands if c.startswith(arg) and command.get(c)([]).is_relevant() ]) # return the choices if there are any if choices: return choices # we want commands to complete before # project names, so if we don't return any # choices above, complete a project name now # if we're completing the first argument if nargs == 1: if proj_path is not None: return os.path.basename(proj_path) # # # # # # # # # sub-commands elif nargs == off + 1: # get our parent command com = args[off - 1] # get its class comcls = command.get(com) # if it is a delegate command if hasattr(comcls, 'get_subcommands'): # get partial subcommand name if user has typed anything # or else use empty string to complete all subcom = args[off] if len(args) == off + 1 else '' # get a list of the parent command's subcommands subcom_choices = comcls.get_subcommands() # if there are any subcommands if subcom_choices: # clean subcommand names (they use command-subcommand format) choices = [k.split('-')[-1] for k in subcom_choices] # return the subcommands that start with the partial subcommand name return " ".join([c for c in choices if c.startswith(subcom)]) # return nothing return ""