-
Notifications
You must be signed in to change notification settings - Fork 5
/
manager.py
141 lines (104 loc) · 3.94 KB
/
manager.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from zope import interface
import os
import sys
import utility
import interfaces
IGNORE = object()
def root_length(a, b):
if b.startswith(a):
return len(a)
else:
return 0
def sort_by_path(path, paths):
return sorted(
paths, key=lambda syspath: root_length(syspath, path), reverse=True)
def find_zope2_product(path):
"""Check the Zope2 magic Products semi-namespace to see if the
path is part of a Product."""
_syspaths = sort_by_path(path, sys.modules["Products"].__path__)
syspath = _syspaths[0]
if not path.startswith(syspath):
return None
product = path[len(syspath)+1:].split(os.path.sep, 2)[0]
return "Products." + product
def find_package(syspaths, path):
"""Determine the Python-package where path is located. If the path is
not located within the Python sys-path, return ``None``."""
_syspaths = sort_by_path(path, syspaths)
syspath = _syspaths[0]
path = os.path.normpath(path)
if not path.startswith(syspath):
if utility.ZOPE_2:
return find_zope2_product(path)
return None
path = path[len(syspath):]
# convert path to dotted filename
if path.startswith(os.path.sep):
path = path[1:]
return path
class TemplateManagerFactory(object):
def __init__(self):
self.manager = TemplateManager()
def __call__(self, layer):
return self.manager
class TemplateManager(object):
interface.implements(interfaces.ITemplateManager)
def __init__(self):
self.syspaths = tuple(sys.path)
self.templates = {}
self.paths = {}
def registerDirectory(self, directory):
for filename in os.listdir(directory):
if filename.endswith('.pt'):
self.paths[filename] = "%s/%s" % (directory, filename)
for template, filename in self.templates.items():
if filename is IGNORE:
del self.templates[template]
def unregisterDirectory(self, directory):
templates = []
for template, filename in self.templates.items():
if filename in self.paths:
templates.append(template)
for filename in os.listdir(directory):
if filename in self.paths:
del self.paths[filename]
for template in templates:
self.registerTemplate(template)
del self.templates[template]
def registerTemplate(self, template):
# only register templates that have a filename attribute
if not hasattr(template, 'filename'):
return
# assert that the template is not already registered
filename = self.templates.get(template)
if filename is IGNORE:
return
# if the template filename matches an override, we're done
paths = self.paths
if paths.get(filename) == template.filename:
return
# verify that override has not been unregistered
if filename is not None and filename not in paths:
# restore original template
template.filename = template._filename
delattr(template, '_filename')
del self.templates[template]
# check if an override exists
path = find_package(self.syspaths, template.filename)
if path is None:
# permanently ignore template
self.templates[template] = IGNORE
return
filename = path.replace(os.path.sep, '.')
if filename in paths:
path = paths[filename]
# save original filename
template._filename = template.filename
# save template and registry and assign path
template.filename = path
self.templates[template] = filename
else:
self.templates[template] = IGNORE
# force cook
template._v_last_read = False
return True