1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 | var l = require('ergo-utils').log.module('ergo-lib-fileinfo');
|
8 | var _ = require('ergo-utils')._;
|
9 | var fs = require('ergo-utils').fs.extend(require('fs-extra'));
|
10 | var path = require('path');
|
11 | const assert = require('assert');
|
12 | var plugin_api = require('../api/plugin')
|
13 | var Promise = require('bluebird');
|
14 |
|
15 | "fileExists,stat,ensureDir,readFile,writeFile,copy".split(',').forEach(function(fn) {
|
16 | fs[fn] = Promise.promisify(fs[fn])
|
17 | });
|
18 |
|
19 |
|
20 | function _fixupFilenameChars(str, space_char_replace) {
|
21 | str = fs.fixupPathSep(str).toLowerCase();
|
22 | var dir = path.dirname(str);
|
23 | str = path.basename(str).replace(/\s/g, space_char_replace || '-');
|
24 | return path.join(dir, str);
|
25 | }
|
26 |
|
27 |
|
28 |
|
29 | function _shouldKeepExisting(file, text)
|
30 | {
|
31 | return Promise.coroutine(function *() {
|
32 | if (!(yield fs.fileExists(file)))
|
33 | return false;
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | try
|
41 | {
|
42 | var existingText = yield fs.readFile(file, "utf8");
|
43 | if (existingText == text)
|
44 | {
|
45 |
|
46 | return true;
|
47 | }
|
48 | }
|
49 | catch (e)
|
50 | {
|
51 | l.logw("Failed to compare existing file " + path.basename(file) + " (will try and overwrite): " + _.niceStackTrace(e));
|
52 |
|
53 | }
|
54 | return false;
|
55 | })();
|
56 | }
|
57 |
|
58 | const USAGE = {
|
59 | IGNORE: -1,
|
60 | COPY: 1,
|
61 | PROCESS: 2
|
62 | }
|
63 |
|
64 | function __determineUsage(_this, context){
|
65 |
|
66 |
|
67 | var chain = plugin_api.buildRenderChain(_this.path, context.config);
|
68 | _this.renderers = chain.renderers;
|
69 |
|
70 |
|
71 |
|
72 |
|
73 | if (!_this.isTheme && _this.isLayout)
|
74 | _this.relPath = path.join("_layouts", path.relative(context.getLayoutPath(), _this.path));
|
75 | if (!_this.isTheme && _this.isPartial)
|
76 | _this.relPath = path.join("_partials", path.relative(context.getPartialsPath(), _this.path));
|
77 |
|
78 | if (_this.isTheme)
|
79 | _this.relPath = path.relative(context.getThemePath(), _this.path);
|
80 |
|
81 |
|
82 |
|
83 | var pathofs = path.dirname(_this.relPath).toLowerCase();
|
84 | _this.destFilename = _fixupFilenameChars(chain.filename, context.config['filename_space_char']);
|
85 | _this.destRelPath = path.join(pathofs, _this.destFilename);
|
86 | _this.destPath = path.join(context.getOutPath(), pathofs, _this.destFilename);
|
87 |
|
88 | var inThemesRoot = _this.isInDir(context.getThemesRootPath());
|
89 |
|
90 | var file_usage = USAGE.IGNORE;
|
91 |
|
92 | if (inThemesRoot && !_this.isTheme)
|
93 | {
|
94 |
|
95 |
|
96 | }
|
97 | else if (_this.isTheme)
|
98 | {
|
99 | |
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 | if (_this.isPartial || _this.isLayout) {
|
116 | file_usage = USAGE.PROCESS;
|
117 | }
|
118 | else {
|
119 |
|
120 | var asset_paths = context.themeconfig.asset_paths;
|
121 | if (asset_paths[0]=='*') {
|
122 | if (_this.destRelPath.indexOf(path.sep)>0)
|
123 |
|
124 | file_usage = USAGE.COPY;
|
125 |
|
126 | asset_paths = asset_paths.slice(1);
|
127 | }
|
128 |
|
129 | if (file_usage==USAGE.IGNORE)
|
130 | asset_paths.forEach(function(folder) {
|
131 | if (fs.isInDir(folder, _this.relPath) ||
|
132 | folder == _this.relPath)
|
133 | file_usage = USAGE.COPY;
|
134 | });
|
135 |
|
136 | |
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 | }
|
152 |
|
153 | }
|
154 | else
|
155 | {
|
156 |
|
157 |
|
158 | if (_this.renderers.length==0 && !(_this.isLayout || _this.isPartial)) {
|
159 |
|
160 | file_usage = USAGE.COPY;
|
161 | }
|
162 | else
|
163 | {
|
164 | file_usage = USAGE.PROCESS;
|
165 | }
|
166 | }
|
167 | _this.usage = file_usage;
|
168 | }
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | function FileInfo(_path, stats, context) {
|
174 | this.path = _path;
|
175 | this.stats = stats;
|
176 |
|
177 | this.isLayout = this.isInDir(context.getLayoutsPath()) || this.isInDir(context.getThemeLayoutsPath());
|
178 | this.isPartial = this.isInDir(context.getPartialsPath()) || this.isInDir(context.getThemePartialsPath());
|
179 | this.isTheme = this.isInDir(context.getThemePath());
|
180 |
|
181 | this.relPath = path.relative(context.getSourcePath(), this.path);
|
182 |
|
183 | this.fields = {content:null};
|
184 | this.renderers = [];
|
185 | __determineUsage(this, context);
|
186 | l.logdIf(this, 2, "Fileinfo '" + this.relPath + "': isLayout("+this.isLayout+"), isPartial("+this.isPartial+"), isTheme("+this.isTheme+"), usage("+this.usage+")")
|
187 | }
|
188 |
|
189 | FileInfo.prototype.constructor = FileInfo;
|
190 |
|
191 | FileInfo.prototype.loadOrCopy = function(context) {
|
192 | var _this = this;
|
193 | return Promise.coroutine(function *() {
|
194 |
|
195 | switch(_this.usage) {
|
196 |
|
197 | case USAGE.PROCESS:
|
198 | l.vlog("Loading '" + _this.relPath+ "'...")
|
199 | _this.fields.content = yield fs.readFile(_this.path);
|
200 | return true;
|
201 |
|
202 | case USAGE.COPY:
|
203 | l.log("Copying '" + _this.relPath + "' to '" + _this.destRelPath + "'...");
|
204 | yield fs.copy(_this.path, _this.destPath, {preserveTimestamps:true});
|
205 |
|
206 |
|
207 |
|
208 | default:
|
209 |
|
210 | _this.fields.content = null;
|
211 | _this.canSave = false;
|
212 | return false;
|
213 | }
|
214 | })();
|
215 | }
|
216 |
|
217 | FileInfo.prototype.canRender = function(context) {
|
218 | return this.renderers.length>0 && !!this.fields && !!this.fields.content;
|
219 | };
|
220 | FileInfo.prototype.renderNext = function(context) {
|
221 | if (this.canRender===false || !this.canRender(context))
|
222 | return false;
|
223 |
|
224 | var r = this.renderers[0];
|
225 | if (r.name!='dummy') l.logdIf(this, 0, "Rendering '"+this.relPath+"' with '" + r.name + "'")
|
226 | this.fields.content = r.render(this.fields, this, context);
|
227 | if (r.name!='dummy') l.logdIf(this, 2, " Content of '"+this.relPath+"' is: " + this.fields.content.substr(0,300))
|
228 | this.renderers.splice(0,1);
|
229 | return this.canRender(context);
|
230 | };
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 | FileInfo.prototype.canSave = function(context) {
|
255 |
|
256 | if (this.usage != USAGE.PROCESS)
|
257 | return false;
|
258 |
|
259 | if (!fs.isInDir(context.getOutPath(), this.destPath)) {
|
260 | l.logd("Output folder is: " + context.getOutPath())
|
261 | l.logw("Attempt to save a file outside the output folder!\nThe offending file is: " + this.destPath + "\n...and was loaded from: " + this.path);
|
262 | return false;
|
263 | }
|
264 |
|
265 | return this.fields && ((!!this.fields.content||!!this.fields.template_content) || this.canRender());
|
266 | }
|
267 |
|
268 | FileInfo.prototype.save = function(context) {
|
269 | var _this = this;
|
270 |
|
271 | return Promise.coroutine(function *() {
|
272 | if (_this.canSave===false || !_this.canSave(context)) {
|
273 | l.log("Skipping save for '" + _this.relPath+"'")
|
274 | return false;
|
275 | }
|
276 |
|
277 | yield fs.ensureDir(path.dirname(_this.destPath));
|
278 | var template = !!_this.fields.template_content;
|
279 | var contents = template ? _this.fields.template_content : _this.fields.content;
|
280 | if ((yield _shouldKeepExisting(_this.destPath, contents))) {
|
281 | l.log("Skipping unchanged '" + _this.relPath+"'")
|
282 | return false;
|
283 | }
|
284 |
|
285 |
|
286 | l.log("Saving "+(template?"(templated) ":"") +"'" + _this.relPath+"' as '"+_this.destRelPath+"'...")
|
287 | yield fs.writeFile(_this.destPath, contents);
|
288 | l.vlog("Write OK")
|
289 | return true;
|
290 | })();
|
291 | };
|
292 |
|
293 | FileInfo.prototype.isRelInDir = function(relDir) { return fs.isInDir(relDir, this.relPath); }
|
294 | FileInfo.prototype.isInDir = function(dir) { return fs.isInDir(dir, this.path); }
|
295 | FileInfo.prototype.USAGE = USAGE;
|
296 |
|
297 |
|
298 |
|
299 | module.exports = FileInfo;
|
300 |
|
301 |
|