cli.py 3.99 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
# iosapplist
# A Python package that lists iOS App Store apps.  (Formerly part of AppBackup.)
#
# Copyright (C) 2008-2014 Scott Zeid
# https://s.zeid.me/projects/appbackup/
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# 
# Except as contained in this notice, the name(s) of the above copyright holders
# shall not be used in advertising or otherwise to promote the sale, use or
# other dealings in this Software without prior written authorization.

# Base CLI engine

31
import sys
32 33 34 35
import types

import commands

36
from . import debug
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
from command import Command
from commandlist import CommandList


__all__ = ["CLI", "CLIError"]


class CLIError(Exception):
 pass


def make_CLI_class():
 class base:
  cls = None
 base = base()
 
 class CLI(object):
  class __meta(type):
   def __new__(mcs, name, bases, dict):
    cls = type.__new__(mcs, name, bases, dict)
    if base.cls is None:
     base.cls = cls
     cls.commands = None
    if cls.commands is not None:
61
     debug("copying command registry from superclass")
62 63 64
     for supercls in cls.__mro__[1:]:
      if issubclass(supercls, base.cls):
       cls.commands = supercls.commands.copy()
65
       break
66
    if cls.commands is None:
67
     debug("making new command registry")
68 69
     cls.commands = CommandList()
     cls.commands.register(commands)
70
    debug("done assigning command registry")
71 72 73 74
    return cls
  __metaclass__ = __meta
  
  __output_format = None
S. Zeid's avatar
S. Zeid committed
75
  __started_any = False
76
  
S. Zeid's avatar
S. Zeid committed
77
  default_command = None
78
  description = None
79
  easter_eggs = False
80
  program = None
81
  version = None
82
  
83 84
  def start(self, argv, default=None.__class__):
   argv = (["shell"] if not self.__started_any else []) + argv
S. Zeid's avatar
S. Zeid committed
85
   debug("running", argv, "in a new instance")
86 87
   cmd, argv = self._lookup(argv, default)
   if not self.__started_any:
88
    cmd._ShellCommand__is_shell = False
89
   self.__started_any = True
90
   r = cmd.run(argv)
S. Zeid's avatar
S. Zeid committed
91 92 93
   debug("finished running", argv)
   return r
  
94
  def __call__(self, argv, default=None.__class__):
95 96
   cmd, argv = self._lookup(argv, default)
   debug("running", argv)
97
   generator = cmd.generate_output(argv)
98 99 100 101 102 103 104 105 106 107
   while True:
    try:
     item = generator.next()
     yield item
    except StopIteration, exc:
     debug("finished running", argv)
     while True:
      raise exc
  
  def _lookup(self, argv, default=None.__class__):
108
   debug("preparing to run", argv)
109 110
   argv0 = argv[0] if len(argv) else None
   cmd = self.commands.get(argv0, None)
111
   default_arg = default
112
   default = self.default_command if default is None.__class__ else default
113
   doing_help = False
114
   if not cmd:
115
    debug("getting object for default command:", default)
116 117 118 119
    cmd = self.commands.get(default, None)
    if cmd:
     argv = [default] + argv
    else:
120
     if argv0 or (not argv0 and default_arg is not None.__class__):
121 122
      raise CLIError("%s is not a valid command" % argv0)
     else:
123
      doing_help = True
124 125
      cmd = self.commands["shell"]
      argv = ["sh", "--help"]
126
   cmd = cmd(self)
127 128
   if doing_help:
    cmd._ShellCommand__is_shell = False
129
   return cmd, argv
130 131 132 133
 
 return CLI

CLI = make_CLI_class()