rename into unfold/*collect*static.py
[unfold.git] / unfold / collectstatic.py
diff --git a/unfold/collectstatic.py b/unfold/collectstatic.py
new file mode 100644 (file)
index 0000000..4fb3bbc
--- /dev/null
@@ -0,0 +1,141 @@
+import os
+from django.conf import settings
+from django.utils.datastructures import SortedDict
+from django.contrib.staticfiles.finders import BaseFinder, FileSystemFinder
+from django.core.files.storage import FileSystemStorage
+
+# DEPRECATED # # http://nicks-liquid-soapbox.blogspot.fr/2011/03/splitting-path-to-list-in-python.html
+# DEPRECATED # def splitpath(path, maxdepth=20):
+# DEPRECATED #      ( head, tail ) = os.path.split(path)
+# DEPRECATED #      return splitpath(head, maxdepth - 1) + [ tail ] \
+# DEPRECATED #          if maxdepth and head and head != path \
+# DEPRECATED #          else [ head or tail ]
+
+# The plugin finder is responsible for collecting JS, CSS and PNG files from
+# the plugins, which are not declared in the myslice.settings file unlike
+# applications.
+class PluginFinder(FileSystemFinder):
+    """
+    A static files finder that looks in the directory of each plugin as
+    specified in the source_dir attribute of the given storage class.
+    """
+    def __init__(self, *args, **kwargs):
+        # The list of plugins that are handled
+        self.locations = []
+        # Mapping of plugin module paths to storage instances
+        self.storages = SortedDict()
+        plugins_dir = self.get_immediate_subdirs(settings.PLUGIN_DIR)
+        for root in plugins_dir:
+            if not os.path.exists(root) or not os.path.isdir(root):
+                continue
+            if ('', root) not in self.locations:
+                self.locations.append(('', root))
+        for _, root in self.locations:
+            filesystem_storage = FileSystemStorage(location=root)
+            filesystem_storage.prefix = ''
+            self.storages[root] = filesystem_storage
+
+    def get_immediate_subdirs(self, dir):
+        return [os.path.join(dir, name, 'static') for name in os.listdir(dir) 
+                if os.path.isdir(os.path.join(dir, name))]
+
+class ThirdPartyFinder(BaseFinder):
+    """
+    A static files finder that looks in the directory of each third-party
+    resources and tries to preserve the location of each file
+    """
+    # third-party/MODULE/path/to/js
+    extensions = {
+        # PREFIX : EXTENSIONS
+        ''   : ('.html',),
+        'js' : ('.js',),
+        'css': ('.css',),
+        'img': ('.png', '.ico',),
+    }
+
+    def find(self, search_path, all=False):
+        """
+        Given a relative file path this ought to find an
+        absolute file path.
+
+        If the ``all`` parameter is ``False`` (default) only
+        the first found file path will be returned; if set
+        to ``True`` a list of all found files paths is returned.
+        """
+        matches = []
+        #all_extensions = reduce(lambda x,y : x + y, extensions.values())
+
+        for (path, dirs, files) in os.walk(settings.THIRDPARTY_DIR):
+            for file in files:
+                name, extension = os.path.splitext(file)
+
+                for type, extensions in self.extensions.items():
+                    if not extension in extensions:
+                        continue
+                    if search_path == os.path.join(type, file):
+                        matched_path = os.path.join(path, file) 
+                        if not all:
+                            return matched_path
+                        matches.append(matched_path)
+        return matches
+
+    def list(self, ignore_patterns):
+        """
+        Given an optional list of paths to ignore, this should return
+        a two item iterable consisting of the relative path and storage
+        instance.
+        """
+
+        for component in os.listdir(settings.THIRDPARTY_DIR):
+            # We are looking forward symlinks only
+            component_path = os.path.join(settings.THIRDPARTY_DIR, component)
+            if not os.path.islink(component_path) or not os.path.isdir(component_path):
+                continue
+                
+            for (path, dirs, files) in os.walk(component_path):
+                for file in files:
+                    name, extension = os.path.splitext(file)
+
+                    for type, extensions in self.extensions.items():
+                        if not extension in extensions:
+                            continue
+                        filesystem_storage = FileSystemStorage(location=path)
+                        filesystem_storage.prefix = type
+                        yield file, filesystem_storage
+            
+# DEPRECATED #         for (path, dirs, files) in os.walk(settings.THIRDPARTY_DIR):
+# DEPRECATED #             component_path = path[len(settings.THIRDPARTY_DIR)+1:]
+# DEPRECATED #             component_name = splitpath(component_path)[0]
+# DEPRECATED #             print "PATH", path, " -- COMPONENT", component_name
+# DEPRECATED #             if not os.path.islink(os.path.join(path, component_name)):
+# DEPRECATED #                 print "IGNORED", component_name
+# DEPRECATED #                 continue
+# DEPRECATED #             print "COMPONENT ADDED: ", component_name
+# DEPRECATED #             print "=="
+# DEPRECATED # 
+# DEPRECATED # 
+# DEPRECATED #             for file in files:
+# DEPRECATED #                 name, extension = os.path.splitext(file)
+# DEPRECATED # 
+# DEPRECATED #                 for type, extensions in self.extensions.items():
+# DEPRECATED #                     if not extension in extensions:
+# DEPRECATED #                         continue
+# DEPRECATED #                     filesystem_storage = FileSystemStorage(location=path)
+# DEPRECATED #                     filesystem_storage.prefix = type
+# DEPRECATED #                     yield file, filesystem_storage
+
+# XXX I commented this since it should be imported from django.contrib.staticfiles.finders -- jordan
+#class BaseFinder(object):
+#    """
+#    A base file finder to be used for custom staticfiles finder classes.
+#    """
+#
+#    def list(self, ignore_patterns):
+#        """
+#        Given an optional list of paths to ignore, this should return
+#        a two item iterable consisting of the relative path and storage
+#        instance.
+#        """
+#        raise NotImplementedError()
+