Fixed #32309 -- Added --exclude option to startapp/startproject management commands.
This commit is contained in:
parent
3686077d46
commit
84c7c4a477
|
@ -1,3 +1,4 @@
|
||||||
|
import argparse
|
||||||
import cgi
|
import cgi
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
|
@ -54,6 +55,14 @@ class TemplateCommand(BaseCommand):
|
||||||
help='The file name(s) to render. Separate multiple file names '
|
help='The file name(s) to render. Separate multiple file names '
|
||||||
'with commas, or use -n multiple times.'
|
'with commas, or use -n multiple times.'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--exclude', '-x',
|
||||||
|
action='append', default=argparse.SUPPRESS, nargs='?', const='',
|
||||||
|
help=(
|
||||||
|
'The directory name(s) to exclude, in addition to .git and '
|
||||||
|
'__pycache__. Can be used multiple times.'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def handle(self, app_or_project, name, target=None, **options):
|
def handle(self, app_or_project, name, target=None, **options):
|
||||||
self.app_or_project = app_or_project
|
self.app_or_project = app_or_project
|
||||||
|
@ -82,8 +91,12 @@ class TemplateCommand(BaseCommand):
|
||||||
|
|
||||||
extensions = tuple(handle_extensions(options['extensions']))
|
extensions = tuple(handle_extensions(options['extensions']))
|
||||||
extra_files = []
|
extra_files = []
|
||||||
|
excluded_directories = ['.git', '__pycache__']
|
||||||
for file in options['files']:
|
for file in options['files']:
|
||||||
extra_files.extend(map(lambda x: x.strip(), file.split(',')))
|
extra_files.extend(map(lambda x: x.strip(), file.split(',')))
|
||||||
|
if exclude := options.get('exclude'):
|
||||||
|
for directory in exclude:
|
||||||
|
excluded_directories.append(directory.strip())
|
||||||
if self.verbosity >= 2:
|
if self.verbosity >= 2:
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
'Rendering %s template files with extensions: %s'
|
'Rendering %s template files with extensions: %s'
|
||||||
|
@ -126,7 +139,10 @@ class TemplateCommand(BaseCommand):
|
||||||
os.makedirs(target_dir, exist_ok=True)
|
os.makedirs(target_dir, exist_ok=True)
|
||||||
|
|
||||||
for dirname in dirs[:]:
|
for dirname in dirs[:]:
|
||||||
if dirname.startswith('.') or dirname == '__pycache__':
|
if 'exclude' not in options:
|
||||||
|
if dirname.startswith('.') or dirname == '__pycache__':
|
||||||
|
dirs.remove(dirname)
|
||||||
|
elif dirname in excluded_directories:
|
||||||
dirs.remove(dirname)
|
dirs.remove(dirname)
|
||||||
|
|
||||||
for filename in files:
|
for filename in files:
|
||||||
|
|
|
@ -1304,6 +1304,14 @@ Specifies which files in the app template (in addition to those matching
|
||||||
``--extension``) should be rendered with the template engine. Defaults to an
|
``--extension``) should be rendered with the template engine. Defaults to an
|
||||||
empty list.
|
empty list.
|
||||||
|
|
||||||
|
.. django-admin-option:: --exclude DIRECTORIES, -x DIRECTORIES
|
||||||
|
|
||||||
|
.. versionadded:: 4.0
|
||||||
|
|
||||||
|
Specifies which directories in the app template should be excluded, in addition
|
||||||
|
to ``.git`` and ``__pycache__``. If this option is not provided, directories
|
||||||
|
named ``__pycache__`` or starting with ``.`` will be excluded.
|
||||||
|
|
||||||
The :class:`template context <django.template.Context>` used for all matching
|
The :class:`template context <django.template.Context>` used for all matching
|
||||||
files is:
|
files is:
|
||||||
|
|
||||||
|
@ -1373,6 +1381,14 @@ Specifies which files in the project template (in addition to those matching
|
||||||
``--extension``) should be rendered with the template engine. Defaults to an
|
``--extension``) should be rendered with the template engine. Defaults to an
|
||||||
empty list.
|
empty list.
|
||||||
|
|
||||||
|
.. django-admin-option:: --exclude DIRECTORIES, -x DIRECTORIES
|
||||||
|
|
||||||
|
.. versionadded:: 4.0
|
||||||
|
|
||||||
|
Specifies which directories in the project template should be excluded, in
|
||||||
|
addition to ``.git`` and ``__pycache__``. If this option is not provided,
|
||||||
|
directories named ``__pycache__`` or starting with ``.`` will be excluded.
|
||||||
|
|
||||||
The :class:`template context <django.template.Context>` used is:
|
The :class:`template context <django.template.Context>` used is:
|
||||||
|
|
||||||
- Any option passed to the ``startproject`` command (among the command's
|
- Any option passed to the ``startproject`` command (among the command's
|
||||||
|
|
|
@ -278,6 +278,9 @@ Management Commands
|
||||||
<django.core.management.BaseCommand.suppressed_base_arguments>` attribute
|
<django.core.management.BaseCommand.suppressed_base_arguments>` attribute
|
||||||
allows suppressing unsupported default command options in the help output.
|
allows suppressing unsupported default command options in the help output.
|
||||||
|
|
||||||
|
* The new :option:`startapp --exclude` and :option:`startproject --exclude`
|
||||||
|
options allow excluding directories from the template.
|
||||||
|
|
||||||
Migrations
|
Migrations
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -2232,6 +2232,70 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
|
||||||
hidden_dir = os.path.join(testproject_dir, '.hidden')
|
hidden_dir = os.path.join(testproject_dir, '.hidden')
|
||||||
self.assertIs(os.path.exists(hidden_dir), False)
|
self.assertIs(os.path.exists(hidden_dir), False)
|
||||||
|
|
||||||
|
def test_custom_project_template_hidden_directory_included(self):
|
||||||
|
"""
|
||||||
|
Template context variables in hidden directories are rendered, if not
|
||||||
|
excluded.
|
||||||
|
"""
|
||||||
|
template_path = os.path.join(custom_templates_dir, 'project_template')
|
||||||
|
project_name = 'custom_project_template_hidden_directories_included'
|
||||||
|
args = [
|
||||||
|
'startproject',
|
||||||
|
'--template',
|
||||||
|
template_path,
|
||||||
|
project_name,
|
||||||
|
'project_dir',
|
||||||
|
'--exclude',
|
||||||
|
]
|
||||||
|
testproject_dir = os.path.join(self.test_dir, 'project_dir')
|
||||||
|
os.mkdir(testproject_dir)
|
||||||
|
|
||||||
|
_, err = self.run_django_admin(args)
|
||||||
|
self.assertNoOutput(err)
|
||||||
|
render_py_path = os.path.join(testproject_dir, '.hidden', 'render.py')
|
||||||
|
with open(render_py_path) as fp:
|
||||||
|
self.assertIn(
|
||||||
|
f'# The {project_name} should be rendered.',
|
||||||
|
fp.read(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_custom_project_template_exclude_directory(self):
|
||||||
|
"""
|
||||||
|
Excluded directories (in addition to .git and __pycache__) are not
|
||||||
|
included in the project.
|
||||||
|
"""
|
||||||
|
template_path = os.path.join(custom_templates_dir, 'project_template')
|
||||||
|
project_name = 'custom_project_with_excluded_directories'
|
||||||
|
args = [
|
||||||
|
'startproject',
|
||||||
|
'--template',
|
||||||
|
template_path,
|
||||||
|
project_name,
|
||||||
|
'project_dir',
|
||||||
|
'--exclude',
|
||||||
|
'additional_dir',
|
||||||
|
'-x',
|
||||||
|
'.hidden',
|
||||||
|
]
|
||||||
|
testproject_dir = os.path.join(self.test_dir, 'project_dir')
|
||||||
|
os.mkdir(testproject_dir)
|
||||||
|
|
||||||
|
_, err = self.run_django_admin(args)
|
||||||
|
self.assertNoOutput(err)
|
||||||
|
excluded_directories = [
|
||||||
|
'.hidden',
|
||||||
|
'additional_dir',
|
||||||
|
'.git',
|
||||||
|
'__pycache__',
|
||||||
|
]
|
||||||
|
for directory in excluded_directories:
|
||||||
|
self.assertIs(
|
||||||
|
os.path.exists(os.path.join(testproject_dir, directory)),
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
not_excluded = os.path.join(testproject_dir, project_name)
|
||||||
|
self.assertIs(os.path.exists(not_excluded), True)
|
||||||
|
|
||||||
|
|
||||||
class StartApp(AdminScriptTestCase):
|
class StartApp(AdminScriptTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue