mirror of
https://github.com/django/django.git
synced 2025-01-03 15:06:09 +00:00
Fixed #4282 -- Made startapp/startproject management commands honor umask.
Co-authored-by: Christian Schmitt <c.schmitt@briefdomain.de>
This commit is contained in:
parent
1555e5850d
commit
59f4796918
@ -181,7 +181,7 @@ class TemplateCommand(BaseCommand):
|
|||||||
if self.verbosity >= 2:
|
if self.verbosity >= 2:
|
||||||
self.stdout.write('Creating %s' % new_path)
|
self.stdout.write('Creating %s' % new_path)
|
||||||
try:
|
try:
|
||||||
shutil.copymode(old_path, new_path)
|
self.apply_umask(old_path, new_path)
|
||||||
self.make_writeable(new_path)
|
self.make_writeable(new_path)
|
||||||
except OSError:
|
except OSError:
|
||||||
self.stderr.write(
|
self.stderr.write(
|
||||||
@ -345,6 +345,12 @@ class TemplateCommand(BaseCommand):
|
|||||||
scheme = template.split(':', 1)[0].lower()
|
scheme = template.split(':', 1)[0].lower()
|
||||||
return scheme in self.url_schemes
|
return scheme in self.url_schemes
|
||||||
|
|
||||||
|
def apply_umask(self, old_path, new_path):
|
||||||
|
current_umask = os.umask(0)
|
||||||
|
os.umask(current_umask)
|
||||||
|
current_mode = stat.S_IMODE(os.stat(old_path).st_mode)
|
||||||
|
os.chmod(new_path, current_mode & ~current_umask)
|
||||||
|
|
||||||
def make_writeable(self, filename):
|
def make_writeable(self, filename):
|
||||||
"""
|
"""
|
||||||
Make sure that the file is writeable.
|
Make sure that the file is writeable.
|
||||||
|
@ -7,6 +7,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
|
import stat
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -32,6 +33,7 @@ from django.test import (
|
|||||||
LiveServerTestCase, SimpleTestCase, TestCase, override_settings,
|
LiveServerTestCase, SimpleTestCase, TestCase, override_settings,
|
||||||
)
|
)
|
||||||
from django.test.utils import captured_stderr, captured_stdout
|
from django.test.utils import captured_stderr, captured_stdout
|
||||||
|
from django.utils.version import PY39
|
||||||
|
|
||||||
custom_templates_dir = os.path.join(os.path.dirname(__file__), 'custom_templates')
|
custom_templates_dir = os.path.join(os.path.dirname(__file__), 'custom_templates')
|
||||||
|
|
||||||
@ -95,7 +97,7 @@ class AdminScriptTestCase(SimpleTestCase):
|
|||||||
paths.append(os.path.dirname(backend_dir))
|
paths.append(os.path.dirname(backend_dir))
|
||||||
return paths
|
return paths
|
||||||
|
|
||||||
def run_test(self, args, settings_file=None, apps=None):
|
def run_test(self, args, settings_file=None, apps=None, umask=None):
|
||||||
base_dir = os.path.dirname(self.test_dir)
|
base_dir = os.path.dirname(self.test_dir)
|
||||||
# The base dir for Django's tests is one level up.
|
# The base dir for Django's tests is one level up.
|
||||||
tests_dir = os.path.dirname(os.path.dirname(__file__))
|
tests_dir = os.path.dirname(os.path.dirname(__file__))
|
||||||
@ -124,11 +126,13 @@ class AdminScriptTestCase(SimpleTestCase):
|
|||||||
cwd=self.test_dir,
|
cwd=self.test_dir,
|
||||||
env=test_environ,
|
env=test_environ,
|
||||||
text=True,
|
text=True,
|
||||||
|
# subprocess.run()'s umask was added in Python 3.9.
|
||||||
|
**({'umask': umask} if umask and PY39 else {}),
|
||||||
)
|
)
|
||||||
return p.stdout, p.stderr
|
return p.stdout, p.stderr
|
||||||
|
|
||||||
def run_django_admin(self, args, settings_file=None):
|
def run_django_admin(self, args, settings_file=None, umask=None):
|
||||||
return self.run_test(['-m', 'django', *args], settings_file)
|
return self.run_test(['-m', 'django', *args], settings_file, umask=umask)
|
||||||
|
|
||||||
def run_manage(self, args, settings_file=None, manage_py=None):
|
def run_manage(self, args, settings_file=None, manage_py=None):
|
||||||
template_manage_py = (
|
template_manage_py = (
|
||||||
@ -2297,6 +2301,29 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
|
|||||||
not_excluded = os.path.join(testproject_dir, project_name)
|
not_excluded = os.path.join(testproject_dir, project_name)
|
||||||
self.assertIs(os.path.exists(not_excluded), True)
|
self.assertIs(os.path.exists(not_excluded), True)
|
||||||
|
|
||||||
|
@unittest.skipIf(
|
||||||
|
sys.platform == 'win32',
|
||||||
|
'Windows only partially supports umasks and chmod.',
|
||||||
|
)
|
||||||
|
@unittest.skipUnless(PY39, "subprocess.run()'s umask was added in Python 3.9.")
|
||||||
|
def test_honor_umask(self):
|
||||||
|
_, err = self.run_django_admin(['startproject', 'testproject'], umask=0o077)
|
||||||
|
self.assertNoOutput(err)
|
||||||
|
testproject_dir = os.path.join(self.test_dir, 'testproject')
|
||||||
|
self.assertIs(os.path.isdir(testproject_dir), True)
|
||||||
|
tests = [
|
||||||
|
(['manage.py'], 0o700),
|
||||||
|
(['testproject'], 0o700),
|
||||||
|
(['testproject', 'settings.py'], 0o600),
|
||||||
|
]
|
||||||
|
for paths, expected_mode in tests:
|
||||||
|
file_path = os.path.join(testproject_dir, *paths)
|
||||||
|
with self.subTest(paths[-1]):
|
||||||
|
self.assertEqual(
|
||||||
|
stat.S_IMODE(os.stat(file_path).st_mode),
|
||||||
|
expected_mode,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class StartApp(AdminScriptTestCase):
|
class StartApp(AdminScriptTestCase):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user