mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +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 | from __future__ import unicode_literals | ||||||
|  |  | ||||||
| import os | import os | ||||||
| import sys |  | ||||||
| from collections import OrderedDict | from collections import OrderedDict | ||||||
| from optparse import make_option | from optparse import make_option | ||||||
|  |  | ||||||
| @@ -82,12 +81,8 @@ class Command(NoArgsCommand): | |||||||
|  |  | ||||||
|         Split off from handle_noargs() to facilitate testing. |         Split off from handle_noargs() to facilitate testing. | ||||||
|         """ |         """ | ||||||
|         if self.symlink: |         if self.symlink and not self.local: | ||||||
|             if sys.platform == 'win32': |             raise CommandError("Can't symlink to a remote destination.") | ||||||
|                 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.clear: |         if self.clear: | ||||||
|             self.clear_dir('') |             self.clear_dir('') | ||||||
| @@ -279,7 +274,18 @@ class Command(NoArgsCommand): | |||||||
|                 os.makedirs(os.path.dirname(full_path)) |                 os.makedirs(os.path.dirname(full_path)) | ||||||
|             except OSError: |             except OSError: | ||||||
|                 pass |                 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: |         if prefixed_path not in self.symlinked_files: | ||||||
|             self.symlinked_files.append(prefixed_path) |             self.symlinked_files.append(prefixed_path) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| import os | import os | ||||||
| import stat | import stat | ||||||
| import sys | import sys | ||||||
|  | import tempfile | ||||||
| from os.path import join, normcase, normpath, abspath, isabs, sep, dirname | from os.path import join, normcase, normpath, abspath, isabs, sep, dirname | ||||||
|  |  | ||||||
| from django.utils.encoding import force_text | from django.utils.encoding import force_text | ||||||
| @@ -99,3 +100,24 @@ def rmtree_errorhandler(func, path, exc_info): | |||||||
|     os.chmod(path, stat.S_IWRITE) |     os.chmod(path, stat.S_IWRITE) | ||||||
|     # use the original function to repeat the operation |     # use the original function to repeat the operation | ||||||
|     func(path) |     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 | * Management commands can now produce syntax colored output under Windows if | ||||||
|   the ANSICON third-party tool is installed and active. |   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 | Models | ||||||
| ^^^^^^ | ^^^^^^ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ from django.core.management import call_command | |||||||
| from django.test import TestCase, override_settings | from django.test import TestCase, override_settings | ||||||
| from django.utils.encoding import force_text | from django.utils.encoding import force_text | ||||||
| from django.utils.functional import empty | 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.utils import six | ||||||
|  |  | ||||||
| from django.contrib.staticfiles import finders, storage | from django.contrib.staticfiles import finders, storage | ||||||
| @@ -645,24 +645,25 @@ class TestCollectionSimpleCachedStorage(BaseCollectionTestCase, | |||||||
|             self.assertNotIn(b"cached/other.css", content) |             self.assertNotIn(b"cached/other.css", content) | ||||||
|             self.assertIn(b"other.deploy12345.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. |         With ``--link``, symbolic links are created. | ||||||
|  |  | ||||||
|         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): |         self.assertTrue(os.path.islink(os.path.join(settings.STATIC_ROOT, 'test.txt'))) | ||||||
|             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'))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestServeStatic(StaticFilesTestCase): | class TestServeStatic(StaticFilesTestCase): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user