separate templates from static files
[myslice.git] / unfold / collectstatic.py
1 import os
2 from django.conf import settings
3 from django.utils.datastructures import SortedDict
4 from django.contrib.staticfiles.finders import BaseFinder, FileSystemFinder
5 from django.core.files.storage import FileSystemStorage
6
7 # DEPRECATED # # http://nicks-liquid-soapbox.blogspot.fr/2011/03/splitting-path-to-list-in-python.html
8 # DEPRECATED # def splitpath(path, maxdepth=20):
9 # DEPRECATED #      ( head, tail ) = os.path.split(path)
10 # DEPRECATED #      return splitpath(head, maxdepth - 1) + [ tail ] \
11 # DEPRECATED #          if maxdepth and head and head != path \
12 # DEPRECATED #          else [ head or tail ]
13
14 # The plugin finder is responsible for collecting JS, CSS and PNG files from
15 # the plugins, which are not declared in the myslice.settings file unlike
16 # applications.
17 class PluginFinder(FileSystemFinder):
18     """
19     A static files finder that looks in the directory of each plugin as
20     specified in the source_dir attribute of the given storage class.
21     """
22     def __init__(self, *args, **kwargs):
23         # The list of plugins that are handled
24         self.locations = []
25         # Mapping of plugin module paths to storage instances
26         self.storages = SortedDict()
27         plugins_dir = self.get_immediate_subdirs(settings.PLUGIN_DIR)
28         for root in plugins_dir:
29             if not os.path.exists(root) or not os.path.isdir(root):
30                 continue
31             if ('', root) not in self.locations:
32                 self.locations.append(('', root))
33         for _, root in self.locations:
34             filesystem_storage = FileSystemStorage(location=root)
35             filesystem_storage.prefix = ''
36             self.storages[root] = filesystem_storage
37
38     def get_immediate_subdirs(self, dir):
39         return [os.path.join(dir, name, 'static') for name in os.listdir(dir) 
40                 if os.path.isdir(os.path.join(dir, name))]
41
42 # as these are a django-specific notion
43 class ThirdPartyFinder(BaseFinder):
44     """
45     A static files finder that looks in the directory of each third-party
46     resources and tries to preserve the location of each file
47     """
48     # third-party/MODULE/path/to/js
49     extensions = {
50         # PREFIX : EXTENSIONS
51 # third party stuff is not expected to provide templates,
52 #        ''   : ('.html',),
53         'js' : ('.js',),
54         'css': ('.css',),
55         'img': ('.png', '.ico',),
56     }
57
58     def find(self, search_path, all=False):
59         """
60         Given a relative file path this ought to find an
61         absolute file path.
62
63         If the ``all`` parameter is ``False`` (default) only
64         the first found file path will be returned; if set
65         to ``True`` a list of all found files paths is returned.
66         """
67         matches = []
68         #all_extensions = reduce(lambda x,y : x + y, extensions.values())
69
70         for (path, dirs, files) in os.walk(settings.THIRDPARTY_DIR):
71             for file in files:
72                 name, extension = os.path.splitext(file)
73
74                 for type, extensions in self.extensions.items():
75                     if not extension in extensions:
76                         continue
77                     if search_path == os.path.join(type, file):
78                         matched_path = os.path.join(path, file) 
79                         if not all:
80                             return matched_path
81                         print 'ThirdPartyFinder, adding',matched_path
82                         matches.append(matched_path)
83         return matches
84
85     def list(self, ignore_patterns):
86         """
87         Given an optional list of paths to ignore, this should return
88         a two item iterable consisting of the relative path and storage
89         instance.
90         """
91
92         for component in os.listdir(settings.THIRDPARTY_DIR):
93             # We are looking forward symlinks only
94             component_path = os.path.join(settings.THIRDPARTY_DIR, component)
95             if not os.path.islink(component_path) or not os.path.isdir(component_path):
96                 continue
97                 
98             for (path, dirs, files) in os.walk(component_path):
99                 for file in files:
100                     name, extension = os.path.splitext(file)
101
102                     for type, extensions in self.extensions.items():
103                         if not extension in extensions:
104                             continue
105                         filesystem_storage = FileSystemStorage(location=path)
106                         filesystem_storage.prefix = type
107                         yield file, filesystem_storage
108             
109 # DEPRECATED #         for (path, dirs, files) in os.walk(settings.THIRDPARTY_DIR):
110 # DEPRECATED #             component_path = path[len(settings.THIRDPARTY_DIR)+1:]
111 # DEPRECATED #             component_name = splitpath(component_path)[0]
112 # DEPRECATED #             print "PATH", path, " -- COMPONENT", component_name
113 # DEPRECATED #             if not os.path.islink(os.path.join(path, component_name)):
114 # DEPRECATED #                 print "IGNORED", component_name
115 # DEPRECATED #                 continue
116 # DEPRECATED #             print "COMPONENT ADDED: ", component_name
117 # DEPRECATED #             print "=="
118 # DEPRECATED # 
119 # DEPRECATED # 
120 # DEPRECATED #             for file in files:
121 # DEPRECATED #                 name, extension = os.path.splitext(file)
122 # DEPRECATED # 
123 # DEPRECATED #                 for type, extensions in self.extensions.items():
124 # DEPRECATED #                     if not extension in extensions:
125 # DEPRECATED #                         continue
126 # DEPRECATED #                     filesystem_storage = FileSystemStorage(location=path)
127 # DEPRECATED #                     filesystem_storage.prefix = type
128 # DEPRECATED #                     yield file, filesystem_storage
129
130 # XXX I commented this since it should be imported from django.contrib.staticfiles.finders -- jordan
131  
132 #class BaseFinder(object):
133 #    """
134 #    A base file finder to be used for custom staticfiles finder classes.
135 #    """
136 #
137 #    def list(self, ignore_patterns):
138 #        """
139 #        Given an optional list of paths to ignore, this should return
140 #        a two item iterable consisting of the relative path and storage
141 #        instance.
142 #        """
143 #        raise NotImplementedError()
144