Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
itminedu
synnefo
Commits
8de23e53
Commit
8de23e53
authored
Jan 16, 2012
by
Kostas Papadimitriou
Browse files
Management utility fix
Handle command discovery of namespaced application modules.
parent
bbd0f38f
Changes
1
Hide whitespace changes
Inline
Side-by-side
snf-webproject/synnefo/webproject/manage.py
View file @
8de23e53
#!/usr/bin/env python
"""
Extented django management module
Most of the code is shared from django.core.management module
to allow us extend the default django ManagementUtility object
used to provide command line interface of the django project
included in snf-webproject package.
The extended class provides the following:
- additional argument for the configuration of the SYNNEFO_SETTINGS_DIR
environmental variable (--settings-dir).
- a fix for management utility to handle custom commands defined in
applications living in namespaced packages (django ticket #14087)
- override of --version command to display the snf-webproject version
"""
from
django.core.management
import
ManagementUtility
,
setup_environ
,
\
BaseCommand
,
LaxOptionParser
,
handle_default_options
BaseCommand
,
LaxOptionParser
,
handle_default_options
,
find_commands
,
\
load_command_class
from
django.core
import
management
from
django.utils.importlib
import
import_module
from
optparse
import
Option
,
make_option
from
synnefo.util.version
import
get_component_version
import
sys
import
os
import
imp
_commands
=
None
def
find_modules
(
name
,
path
=
None
):
"""Find all modules with name 'name'
Unlike find_module in the imp package this returns a list of all
matched modules.
"""
results
=
[]
if
path
is
None
:
path
=
sys
.
path
for
p
in
path
:
importer
=
sys
.
path_importer_cache
.
get
(
p
,
None
)
if
importer
is
None
:
find_module
=
imp
.
find_module
else
:
find_module
=
importer
.
find_module
try
:
result
=
find_module
(
name
,
[
p
])
if
result
is
not
None
:
results
.
append
(
result
)
except
ImportError
:
pass
if
not
results
:
raise
ImportError
(
"No module named %.200s"
%
name
)
return
results
def
find_management_module
(
app_name
):
"""
Determines the path to the management module for the given app_name,
without actually importing the application or the management module.
Raises ImportError if the management module cannot be found for any reason.
"""
parts
=
app_name
.
split
(
'.'
)
parts
.
append
(
'management'
)
parts
.
reverse
()
part
=
parts
.
pop
()
paths
=
None
# When using manage.py, the project module is added to the path,
# loaded, then removed from the path. This means that
# testproject.testapp.models can be loaded in future, even if
# testproject isn't in the path. When looking for the management
# module, we need look for the case where the project name is part
# of the app_name but the project directory itself isn't on the path.
try
:
modules
=
find_modules
(
part
,
paths
)
paths
=
[
m
[
1
]
for
m
in
modules
]
except
ImportError
,
e
:
if
os
.
path
.
basename
(
os
.
getcwd
())
!=
part
:
raise
e
while
parts
:
part
=
parts
.
pop
()
modules
=
find_modules
(
part
,
paths
)
paths
=
[
m
[
1
]
for
m
in
modules
]
return
paths
[
0
]
def
get_commands
():
"""
Returns a dictionary mapping command names to their callback applications.
This works by looking for a management.commands package in django.core, and
in each installed application -- if a commands package exists, all commands
in that package are registered.
Core commands are always included. If a settings module has been
specified, user-defined commands will also be included, the
startproject command will be disabled, and the startapp command
will be modified to use the directory in which the settings module appears.
The dictionary is in the format {command_name: app_name}. Key-value
pairs from this dictionary can then be used in calls to
load_command_class(app_name, command_name)
If a specific version of a command must be loaded (e.g., with the
startapp command), the instantiated module can be placed in the
dictionary in place of the application name.
The dictionary is cached on the first call and reused on subsequent
calls.
"""
global
_commands
if
_commands
is
None
:
_commands
=
dict
([(
name
,
'django.core'
)
for
name
in
\
find_commands
(
management
.
__path__
[
0
])])
# Find the installed apps
try
:
from
django.conf
import
settings
apps
=
settings
.
INSTALLED_APPS
except
(
AttributeError
,
EnvironmentError
,
ImportError
):
apps
=
[]
# Find the project directory
try
:
from
django.conf
import
settings
module
=
import_module
(
settings
.
SETTINGS_MODULE
)
project_directory
=
setup_environ
(
module
,
settings
.
SETTINGS_MODULE
)
except
(
AttributeError
,
EnvironmentError
,
ImportError
,
KeyError
):
project_directory
=
None
# Find and load the management module for each installed app.
for
app_name
in
apps
:
try
:
path
=
find_management_module
(
app_name
)
_commands
.
update
(
dict
([(
name
,
app_name
)
for
name
in
find_commands
(
path
)]))
except
ImportError
:
pass
# No management module - ignore this app
if
project_directory
:
# Remove the "startproject" command from self.commands, because
# that's a django-admin.py command, not a manage.py command.
del
_commands
[
'startproject'
]
# Override the startapp command so that it always uses the
# project_directory, not the current working directory
# (which is default).
from
django.core.management.commands.startapp
import
ProjectCommand
_commands
[
'startapp'
]
=
ProjectCommand
(
project_directory
)
return
_commands
class
SynnefoManagementUtility
(
ManagementUtility
):
"""
...
...
@@ -76,6 +221,37 @@ class SynnefoManagementUtility(ManagementUtility):
else
:
self
.
fetch_command
(
subcommand
).
run_from_argv
(
self
.
argv
)
def
main_help_text
(
self
):
"""
Returns the script's main help text, as a string.
"""
usage
=
[
''
,
"Type '%s help <subcommand>' for help on a specific subcommand."
%
self
.
prog_name
,
''
]
usage
.
append
(
'Available subcommands:'
)
commands
=
get_commands
().
keys
()
commands
.
sort
()
for
cmd
in
commands
:
usage
.
append
(
' %s'
%
cmd
)
return
'
\n
'
.
join
(
usage
)
def
fetch_command
(
self
,
subcommand
):
"""
Tries to fetch the given subcommand, printing a message with the
appropriate command called from the command line (usually
"django-admin.py" or "manage.py") if it can't be found.
"""
try
:
app_name
=
get_commands
()[
subcommand
]
except
KeyError
:
sys
.
stderr
.
write
(
"Unknown command: %r
\n
Type '%s help' for usage.
\n
"
%
\
(
subcommand
,
self
.
prog_name
))
sys
.
exit
(
1
)
if
isinstance
(
app_name
,
BaseCommand
):
# If the command is already loaded, use it directly.
klass
=
app_name
else
:
klass
=
load_command_class
(
app_name
,
subcommand
)
return
klass
def
main
():
# no need to run setup_environ
# we already know our project
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment