mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #21482 -- Uplifted restriction of collectstatic using symlink option in Windows NT 6.
Original patch by Vajrasky Kok. Reviewed by Florian Apolloner, Aymeric Augustin.
This commit is contained in:
		| @@ -1,7 +1,6 @@ | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| import os | ||||
| import sys | ||||
| from collections import OrderedDict | ||||
| from optparse import make_option | ||||
|  | ||||
| @@ -82,12 +81,8 @@ class Command(NoArgsCommand): | ||||
|  | ||||
|         Split off from handle_noargs() to facilitate testing. | ||||
|         """ | ||||
|         if self.symlink: | ||||
|             if sys.platform == 'win32': | ||||
|                 raise CommandError("Symlinking is not supported by this " | ||||
|                                    "platform (%s)." % sys.platform) | ||||
|             if not self.local: | ||||
|                 raise CommandError("Can't symlink to a remote destination.") | ||||
|         if self.symlink and not self.local: | ||||
|             raise CommandError("Can't symlink to a remote destination.") | ||||
|  | ||||
|         if self.clear: | ||||
|             self.clear_dir('') | ||||
| @@ -279,7 +274,18 @@ class Command(NoArgsCommand): | ||||
|                 os.makedirs(os.path.dirname(full_path)) | ||||
|             except OSError: | ||||
|                 pass | ||||
|             os.symlink(source_path, full_path) | ||||
|             try: | ||||
|                 os.symlink(source_path, full_path) | ||||
|             except AttributeError: | ||||
|                 import platform | ||||
|                 raise CommandError("Symlinking is not supported by Python %s." % | ||||
|                                    platform.python_version()) | ||||
|             except NotImplementedError: | ||||
|                 import platform | ||||
|                 raise CommandError("Symlinking is not supported in this " | ||||
|                                    "platform (%s)." % platform.platform()) | ||||
|             except OSError as e: | ||||
|                 raise CommandError(e) | ||||
|         if prefixed_path not in self.symlinked_files: | ||||
|             self.symlinked_files.append(prefixed_path) | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import os | ||||
| import stat | ||||
| import sys | ||||
| import tempfile | ||||
| from os.path import join, normcase, normpath, abspath, isabs, sep, dirname | ||||
|  | ||||
| from django.utils.encoding import force_text | ||||
| @@ -99,3 +100,24 @@ def rmtree_errorhandler(func, path, exc_info): | ||||
|     os.chmod(path, stat.S_IWRITE) | ||||
|     # use the original function to repeat the operation | ||||
|     func(path) | ||||
|  | ||||
|  | ||||
| def symlinks_supported(): | ||||
|     """ | ||||
|     A function to check if creating symlinks are supported in the | ||||
|     host platform and/or if they are allowed to be created (e.g. | ||||
|     on Windows it requires admin permissions). | ||||
|     """ | ||||
|     tmpdir = tempfile.mkdtemp() | ||||
|     original_path = os.path.join(tmpdir, 'original') | ||||
|     symlink_path = os.path.join(tmpdir, 'symlink') | ||||
|     os.makedirs(original_path) | ||||
|     try: | ||||
|         os.symlink(original_path, symlink_path) | ||||
|         supported = True | ||||
|     except (OSError, NotImplementedError, AttributeError): | ||||
|         supported = False | ||||
|     else: | ||||
|         os.remove(symlink_path) | ||||
|     finally: | ||||
|         return supported | ||||
|   | ||||
| @@ -565,6 +565,9 @@ Management Commands | ||||
| * Management commands can now produce syntax colored output under Windows if | ||||
|   the ANSICON third-party tool is installed and active. | ||||
|  | ||||
| * :djadmin:`collectstatic` command with symlink option is now supported on | ||||
|   Windows NT 6 (Windows Vista and newer). | ||||
|  | ||||
| Models | ||||
| ^^^^^^ | ||||
|  | ||||
|   | ||||
| @@ -17,7 +17,7 @@ from django.core.management import call_command | ||||
| from django.test import TestCase, override_settings | ||||
| from django.utils.encoding import force_text | ||||
| from django.utils.functional import empty | ||||
| from django.utils._os import rmtree_errorhandler, upath | ||||
| from django.utils._os import rmtree_errorhandler, upath, symlinks_supported | ||||
| from django.utils import six | ||||
|  | ||||
| from django.contrib.staticfiles import finders, storage | ||||
| @@ -645,24 +645,25 @@ class TestCollectionSimpleCachedStorage(BaseCollectionTestCase, | ||||
|             self.assertNotIn(b"cached/other.css", content) | ||||
|             self.assertIn(b"other.deploy12345.css", content) | ||||
|  | ||||
| if sys.platform != 'win32': | ||||
|  | ||||
|     class TestCollectionLinks(CollectionTestCase, TestDefaults): | ||||
| @unittest.skipUnless(symlinks_supported(), | ||||
|                      "Must be able to symlink to run this test.") | ||||
| class TestCollectionLinks(CollectionTestCase, TestDefaults): | ||||
|     """ | ||||
|     Test ``--link`` option for ``collectstatic`` management command. | ||||
|  | ||||
|     Note that by inheriting ``TestDefaults`` we repeat all | ||||
|     the standard file resolving tests here, to make sure using | ||||
|     ``--link`` does not change the file-selection semantics. | ||||
|     """ | ||||
|     def run_collectstatic(self): | ||||
|         super(TestCollectionLinks, self).run_collectstatic(link=True) | ||||
|  | ||||
|     def test_links_created(self): | ||||
|         """ | ||||
|         Test ``--link`` option for ``collectstatic`` management command. | ||||
|  | ||||
|         Note that by inheriting ``TestDefaults`` we repeat all | ||||
|         the standard file resolving tests here, to make sure using | ||||
|         ``--link`` does not change the file-selection semantics. | ||||
|         With ``--link``, symbolic links are created. | ||||
|         """ | ||||
|         def run_collectstatic(self): | ||||
|             super(TestCollectionLinks, self).run_collectstatic(link=True) | ||||
|  | ||||
|         def test_links_created(self): | ||||
|             """ | ||||
|             With ``--link``, symbolic links are created. | ||||
|             """ | ||||
|             self.assertTrue(os.path.islink(os.path.join(settings.STATIC_ROOT, 'test.txt'))) | ||||
|         self.assertTrue(os.path.islink(os.path.join(settings.STATIC_ROOT, 'test.txt'))) | ||||
|  | ||||
|  | ||||
| class TestServeStatic(StaticFilesTestCase): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user