-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcompiled_loader.go
194 lines (160 loc) · 5.44 KB
/
compiled_loader.go
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package twig
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
// CompiledLoader loads templates from compiled files
type CompiledLoader struct {
directory string
fileExtension string
}
// NewCompiledLoader creates a new compiled loader
func NewCompiledLoader(directory string) *CompiledLoader {
return &CompiledLoader{
directory: directory,
fileExtension: ".twig.compiled",
}
}
// Load implements the Loader interface
func (l *CompiledLoader) Load(name string) (string, error) {
filePath := filepath.Join(l.directory, name+l.fileExtension)
// Check if the file exists
if _, err := os.Stat(filePath); os.IsNotExist(err) {
return "", fmt.Errorf("compiled template file not found: %s", filePath)
}
// Read the file
data, err := ioutil.ReadFile(filePath)
if err != nil {
return "", fmt.Errorf("failed to read compiled template file: %w", err)
}
// Deserialize the compiled template
compiled, err := DeserializeCompiledTemplate(data)
if err != nil {
return "", fmt.Errorf("failed to deserialize compiled template: %w", err)
}
// Return the source from the compiled template
return compiled.Source, nil
}
// Exists checks if a compiled template exists
func (l *CompiledLoader) Exists(name string) bool {
filePath := filepath.Join(l.directory, name+l.fileExtension)
_, err := os.Stat(filePath)
return err == nil
}
// LoadCompiled loads a compiled template from file and registers it with the engine
func (l *CompiledLoader) LoadCompiled(engine *Engine, name string) error {
// The Load method of this loader already handles reading the compiled template
// Just force a load of the template by the engine
_, err := engine.Load(name)
return err
}
// SaveCompiled saves a compiled template to file
func (l *CompiledLoader) SaveCompiled(engine *Engine, name string) error {
// Get the template
template, err := engine.Load(name)
if err != nil {
return err
}
// Compile the template
compiled, err := template.Compile()
if err != nil {
return err
}
// Serialize the compiled template
data, err := SerializeCompiledTemplate(compiled)
if err != nil {
return err
}
// Ensure the directory exists
if err := os.MkdirAll(l.directory, 0755); err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
// Save the compiled template
filePath := filepath.Join(l.directory, name+l.fileExtension)
if err := ioutil.WriteFile(filePath, data, 0644); err != nil {
return fmt.Errorf("failed to write compiled template file: %w", err)
}
return nil
}
// CompileAll compiles all templates loaded by the engine and saves them
func (l *CompiledLoader) CompileAll(engine *Engine) error {
// Get all cached template names
templateNames := engine.GetCachedTemplateNames()
// Compile and save each template
for _, name := range templateNames {
if err := l.SaveCompiled(engine, name); err != nil {
return fmt.Errorf("failed to compile template %s: %w", name, err)
}
}
return nil
}
// LoadAll loads all compiled templates from the directory
func (l *CompiledLoader) LoadAll(engine *Engine) error {
// Register loader with the engine
engine.RegisterLoader(l)
LogInfo("Loading all compiled templates from directory: %s", l.directory)
// List all files in the directory
files, err := ioutil.ReadDir(l.directory)
if err != nil {
LogError(err, fmt.Sprintf("Failed to read directory: %s", l.directory))
return fmt.Errorf("failed to read compiled templates directory '%s': %w", l.directory, err)
}
// Collect errors during loading
var loadErrors []error
var loadedCount int
// Load each compiled template
for _, file := range files {
// Skip directories
if file.IsDir() {
LogVerbose("Skipping directory: %s", file.Name())
continue
}
// Check if it's a compiled template file
ext := filepath.Ext(file.Name())
if ext == l.fileExtension {
// Get the template name (filename without extension)
name := file.Name()[:len(file.Name())-len(ext)]
LogInfo("Loading compiled template: %s", name)
// Load the template
if err := l.LoadCompiled(engine, name); err != nil {
// Collect the error but continue loading other templates
errWithContext := fmt.Errorf("failed to load compiled template '%s' from '%s': %w",
name, filepath.Join(l.directory, file.Name()), err)
LogError(errWithContext)
loadErrors = append(loadErrors, errWithContext)
} else {
loadedCount++
LogInfo("Successfully loaded compiled template: %s", name)
}
} else {
LogVerbose("Skipping non-template file: %s", file.Name())
}
}
// If there were any errors, return a combined error with detailed information
if len(loadErrors) > 0 {
LogWarning("Completed loading with %d success(es) and %d error(s)", loadedCount, len(loadErrors))
errDetails := strings.Builder{}
errDetails.WriteString(fmt.Sprintf("%d out of %d template(s) failed to load:\n",
len(loadErrors), loadedCount+len(loadErrors)))
for i, err := range loadErrors {
errDetails.WriteString(fmt.Sprintf(" %d) %s\n", i+1, err.Error()))
}
return fmt.Errorf("errors loading compiled templates: %s", errDetails.String())
}
LogInfo("Successfully loaded %d compiled templates", loadedCount)
return nil
}
// Implement TimestampAwareLoader interface
func (l *CompiledLoader) GetModifiedTime(name string) (int64, error) {
filePath := filepath.Join(l.directory, name+l.fileExtension)
// Check if the file exists
info, err := os.Stat(filePath)
if err != nil {
return 0, err
}
// Return the file modification time
return info.ModTime().Unix(), nil
}