Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #21482 -- Uplifted restriction of collectstatic using symlink o…

…ption in Windows NT 6.

Original patch by Vajrasky Kok. Reviewed by Florian Apolloner, Aymeric Augustin.
  • Loading branch information...
commit 5cc0555603167c7532b7b714e2672687da8f106e 1 parent 9c4ad45
@jezdez jezdez authored
View
22 django/contrib/staticfiles/management/commands/collectstatic.py
@@ -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 @@ def collect(self):
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 @@ def link_file(self, path, prefixed_path, source_storage):
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)
View
22 django/utils/_os.py
@@ -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
View
3  docs/releases/1.7.txt
@@ -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
^^^^^^
View
33 tests/staticfiles_tests/tests.py
@@ -17,7 +17,7 @@
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 @@ def test_template_tag_simple_content(self):
self.assertNotIn(b"cached/other.css", content)
self.assertIn(b"other.deploy12345.css", content)
-if sys.platform != 'win32':
- class TestCollectionLinks(CollectionTestCase, TestDefaults):
- """
- Test ``--link`` option for ``collectstatic`` management command.
+@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)
+ 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):
- """
- With ``--link``, symbolic links are created.
- """
- self.assertTrue(os.path.islink(os.path.join(settings.STATIC_ROOT, 'test.txt')))
+ 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):
Please sign in to comment.
Something went wrong with that request. Please try again.