15 | | # Let the ImportError propogate. |
16 | | return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')() |
| 15 | command_dir = os.path.join(path, 'commands') |
| 16 | try: |
| 17 | return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] |
| 18 | except OSError: |
| 19 | return [] |
| 20 | |
| 21 | def load_default_commands(): |
| 22 | """ |
| 23 | Returns a dictionary of instances of all available Command classes. |
| 24 | |
| 25 | This works by looking for and loading all Python modules in the |
| 26 | django.core.management.commands package. |
| 27 | |
| 28 | The dictionary is in the format {name: command_instance}. |
| 29 | """ |
| 30 | return dict([(name, getattr(__import__('django.core.management.commands.%s' % (name), {}, {}, ['Command']), 'Command')()) for name in find_commands(__path__[0])]) |
| 31 | |
| 32 | def load_project_commands(): |
| 33 | """ |
| 34 | Returns a dictionary of instances of all available Command classes. |
| 35 | |
| 36 | It looks for a management.commands package in each installed application |
| 37 | -- if a commands package exists, it loads all commands in that |
| 38 | application and raises an AttributeError if a command doesn't contain a |
| 39 | Command instance. |
| 40 | |
| 41 | The dictionary is in the format {name: command_instance}. |
| 42 | """ |
| 43 | |
| 44 | commands = {} |
| 45 | |
| 46 | from django.db import models |
| 47 | |
| 48 | # Get commands from all installed apps |
| 49 | for app in models.get_apps(): |
| 50 | try: |
| 51 | app_name = '.'.join(app.__name__.split('.')[:-1]) |
| 52 | path = os.path.join(os.path.dirname(app.__file__),'management') |
| 53 | commands.update(dict([(name, getattr(__import__('%s.management.commands.%s' % (app_name, name), {}, {}, ['Command']), 'Command')()) for name in find_commands(path)])) |
| 54 | except AttributeError: |
| 55 | sys.stderr.write("Management command '%s' in application '%s' doesn't contain a Command instance.\n" % (name, app_name)) |
| 56 | sys.exit(1) |
| 57 | |
| 58 | return commands |
55 | 84 | def usage(self): |
56 | 85 | """ |
57 | 86 | Returns a usage string, for use with optparse. |
58 | 87 | |
59 | 88 | The string doesn't include the options (e.g., "--verbose"), because |
60 | 89 | optparse puts those in automatically. |
61 | 90 | """ |
62 | 91 | usage = ["%prog command [options]\nactions:"] |
63 | 92 | commands = self.commands.items() |
64 | 93 | commands.sort() |
65 | 94 | for name, cmd in commands: |
66 | 95 | usage.append(' %s %s' % (name, cmd.args)) |
67 | 96 | usage.extend(textwrap.wrap(cmd.help, initial_indent=' ', subsequent_indent=' ')) |
68 | 97 | usage.append('') |
69 | 98 | return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space. |
70 | 99 | |
71 | 100 | def execute(self, argv=None): |
72 | 101 | """ |
73 | 102 | Parses the given argv from the command line, determines which command |
74 | 103 | to run and runs the command. |
75 | 104 | """ |
76 | 105 | if argv is None: |
77 | 106 | argv = sys.argv |
78 | 107 | |
79 | 108 | # Create the parser object and parse the command-line args. |
80 | 109 | # TODO: Ideally each Command class would register its own options for |
81 | 110 | # add_option(), but we'd need to figure out how to allow for multiple |
82 | 111 | # Commands using the same options. The optparse library gets in the way |
83 | 112 | # by checking for conflicts: |
84 | 113 | # http://docs.python.org/lib/optparse-conflicts-between-options.html |
85 | 114 | parser = OptionParser(usage=self.usage(), version=get_version()) |
86 | 115 | parser.add_option('--settings', |
87 | 116 | help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.') |
88 | 117 | parser.add_option('--pythonpath', |
89 | 118 | help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".') |
90 | 119 | parser.add_option('--plain', action='store_true', dest='plain', |
91 | 120 | help='When using "shell": Tells Django to use plain Python, not IPython.') |
92 | 121 | parser.add_option('--noinput', action='store_false', dest='interactive', default=True, |
93 | 122 | help='Tells Django to NOT prompt the user for input of any kind.') |
94 | 123 | parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True, |
95 | 124 | help='When using "runserver": Tells Django to NOT use the auto-reloader.') |
96 | 125 | parser.add_option('--format', default='json', dest='format', |
97 | 126 | help='Specifies the output serialization format for fixtures') |
98 | 127 | parser.add_option('--indent', default=None, dest='indent', |
99 | 128 | type='int', help='Specifies the indent level to use when pretty-printing output') |
100 | 129 | parser.add_option('--verbosity', action='store', dest='verbosity', default='1', |
101 | 130 | type='choice', choices=['0', '1', '2'], |
102 | 131 | help='Verbosity level; 0=minimal output, 1=normal output, 2=all output') |
103 | 132 | parser.add_option('--adminmedia', dest='admin_media_path', default='', |
104 | 133 | help='When using "runserver": Specifies the directory from which to serve admin media.') |
105 | 134 | options, args = parser.parse_args(argv[1:]) |
106 | 135 | |
107 | 136 | # If the 'settings' or 'pythonpath' options were submitted, activate those. |
108 | 137 | if options.settings: |
109 | 138 | os.environ['DJANGO_SETTINGS_MODULE'] = options.settings |
110 | 139 | if options.pythonpath: |
111 | 140 | sys.path.insert(0, options.pythonpath) |
112 | 141 | |
113 | 142 | # Run the appropriate command. |
114 | 143 | try: |
115 | 144 | command_name = args[0] |
116 | 145 | except IndexError: |
117 | 146 | sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0])) |
118 | 147 | sys.exit(1) |
119 | 148 | try: |
120 | 149 | command = self.commands[command_name] |
121 | 150 | except KeyError: |
122 | 151 | sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0]))) |
123 | 152 | sys.exit(1) |
124 | 153 | command.execute(*args[1:], **options.__dict__) |
125 | 154 | |
126 | 155 | class ProjectManagementUtility(ManagementUtility): |
127 | 156 | """ |
128 | 157 | A ManagementUtility that is specific to a particular Django project. |
129 | 158 | As such, its commands are slightly different than those of its parent |
130 | 159 | class. |
131 | 160 | |
132 | 161 | In practice, this class represents manage.py, whereas ManagementUtility |
133 | 162 | represents django-admin.py. |
134 | 163 | """ |
135 | 164 | def __init__(self, project_directory): |
136 | 165 | super(ProjectManagementUtility, self).__init__() |
137 | 166 | |
138 | 167 | # Remove the "startproject" command from self.commands, because |
139 | 168 | # that's a django-admin.py command, not a manage.py command. |
140 | 169 | del self.commands['startproject'] |
141 | 170 | |
142 | 171 | # Override the startapp command so that it always uses the |
143 | 172 | # project_directory, not the current working directory (which is default). |
144 | 173 | from django.core.management.commands.startapp import ProjectCommand |
145 | 174 | self.commands['startapp'] = ProjectCommand(project_directory) |
146 | 175 | |
147 | 176 | def setup_environ(settings_mod): |
148 | 177 | """ |
149 | 178 | Configure the runtime environment. This can also be used by external |
150 | 179 | scripts wanting to set up a similar environment to manage.py. |
151 | 180 | """ |
152 | 181 | # Add this project to sys.path so that it's importable in the conventional |
153 | 182 | # way. For example, if this file (manage.py) lives in a directory |
154 | 183 | # "myproject", this code would add "/path/to/myproject" to sys.path. |
155 | 184 | project_directory, settings_filename = os.path.split(settings_mod.__file__) |
156 | 185 | project_name = os.path.basename(project_directory) |
157 | 186 | settings_name = os.path.splitext(settings_filename)[0] |
158 | 187 | sys.path.append(os.path.join(project_directory, '..')) |
159 | 188 | project_module = __import__(project_name, {}, {}, ['']) |
160 | 189 | sys.path.pop() |
161 | 190 | |
162 | 191 | # Set DJANGO_SETTINGS_MODULE appropriately. |
163 | 192 | os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name) |