marko/lib/compiler/compiler_server.js
2014-01-23 21:30:54 -07:00

230 lines
9.1 KiB
JavaScript

/*
* Copyright 2011 eBay Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @extension Server
*/
var createError = require('raptor-util').createError;
'use strict';
var compiler = require('raptor-templates/compiler');
var logger = require('raptor-logging').logger('raptor/templating/compiler');
var resources = require('raptor-resources');
var packaging = require('raptor-packaging');
var discoveryComplete = false;
var searchPathListenerHandler = null;
var watchingEnabled = false;
var loadedTaglibPaths = {};
var taglibsLastModified = null;
Object.defineProperty(compiler, 'workDir', {
get: function () {
return this._workDir;
},
set: function (val) {
this.setWorkDir(val);
}
});
require('raptor-util').extend(compiler, {
enableWatching: function () {
watchingEnabled = true;
},
disableWatching: function () {
watchingEnabled = false;
},
isWatchingEnabled: function () {
return watchingEnabled;
},
setWatchingEnabled: function (enabled) {
watchingEnabled = enabled;
},
compileAndLoadResource: function (path, options) {
this.createCompiler(options).compileAndLoadResource(path);
},
compileResource: function (path, options) {
return this.createCompiler(options).compileResource(path);
},
loadModuleTaglibs: function (moduleName) {
var manifest = require('raptor-packaging').getModuleManifest(moduleName);
if (manifest) {
this.loadPackageTaglibs(manifest);
}
},
loadPackageTaglibs: function (manifest) {
var taglibs = manifest.getRaptorProp('taglibs');
if (taglibs) {
raptor.forEach(taglibs, function (rtldPath) {
var key = manifest.getURL() + ':' + rtldPath;
if (!loadedTaglibPaths[key]) {
loadedTaglibPaths[key] = true;
var rtldResource = manifest.resolveResource(rtldPath);
if (!rtldResource || !rtldResource.exists()) {
throw createError(new Error('Raptor TLD "' + rtldPath + '" not found for manifest "' + manifest.getURL() + '"'));
}
this.loadTaglib(rtldResource);
}
}, this);
}
},
findAndLoadTaglib: function (uri) {
var pathBuilders = [
function (uri) {
var path = uri;
if (!path.endsWith('.rtld')) {
path += '.rtld';
}
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
},
function (uri) {
var lastSlash = uri.lastIndexOf('/');
var shortName = lastSlash === -1 ? uri : uri.substring(lastSlash + 1);
path = uri + '/' + shortName;
if (!path.endsWith('.rtld')) {
path += '.rtld';
}
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
}
];
for (var i = 0, len = pathBuilders.length; i < len; i++) {
var pathBuilder = pathBuilders[i];
var path = pathBuilder(uri);
var taglibResource = require('raptor-resources').findResource(path);
if (taglibResource && taglibResource.exists()) {
var taglib = require('raptor-templates/compiler').loadTaglib(taglibResource);
this.addTaglibAlias(taglib.uri, uri);
return;
}
}
// Last resort: see if the URI is associated with a module that registers
// the taglibs...
require('raptor-templates/compiler').loadModuleTaglibs(uri);
},
discoverTaglibs: function (force) {
if (discoveryComplete && force !== true) {
return;
}
discoveryComplete = true;
this.clearTaglibs();
loadedTaglibPaths = {};
packaging.forEachTopLevelPackageManifest(this.loadPackageTaglibs, this);
resources.forEach('/rtlds', function (rtldsResource) {
if (rtldsResource.isDirectory()) {
rtldsResource.forEachChild(function (rtldResource) {
if (rtldResource.isFile() && rtldResource.getName().endsWith('.rtld')) {
this.loadTaglib(rtldResource);
}
}, this);
}
}, this);
if (!searchPathListenerHandler) {
searchPathListenerHandler = require('raptor-resources').getSearchPath().subscribe('modified', function () {
discoveryComplete = false;
this.discoverTaglibs(); //If the search path is modified then rediscover the taglibs
}, this);
}
},
loadTaglib: function (taglibResource) {
this.recordLoadedTaglib(taglibResource);
var xml = taglibResource.readAsString();
return this.loadTaglibXml(xml, taglibResource);
},
recordLoadedTaglib: function (taglibResource) {
var workDir = this.getWorkDir();
if (workDir) {
var taglibsLastModified = this._readTaglibsLastModified(workDir);
taglibsLastModified.lastModified = Math.max(taglibResource.lastModified(), taglibsLastModified.lastModified || 0);
taglibsLastModified.urls[taglibResource.getURL()] = true;
var newStr = taglibsLastModified.lastModified + '\n' + Object.keys(taglibsLastModified.urls).join('\n');
if (newStr != taglibsLastModified.written) {
taglibsLastModified.written = newStr;
this._taglibsWorkFile.writeAsString(newStr);
}
}
},
_readTaglibsLastModified: function (workDir) {
var taglibsWorkFile = this._taglibsWorkFile;
if (taglibsLastModified == null) {
taglibsLastModified = {
lastModified: null,
urls: {},
written: null
};
if (taglibsWorkFile.exists()) {
try {
taglibsLastModified.str = taglibsWorkFile.readAsString();
var lastModifiedEnd = taglibsLastModified.str.indexOf('\n');
taglibsLastModified.lastModified = parseInt(taglibsLastModified.str.substring(0, lastModifiedEnd), 10);
taglibsLastModified.str.substring(lastModifiedEnd + 1).split('\n').forEach(function (url) {
taglibsLastModified.urls[url] = true;
});
} catch (e) {
logger.warn('Unable to read "' + taglibsWorkFile.getAbsolutePath() + '". Exception: ' + e, e);
}
}
}
return taglibsLastModified;
},
_validateWorkDir: function (workDir) {
if (!workDir) {
return;
}
logger.debug('Validating work directory at path "' + workDir + '"...');
var taglibsLastModified = this._readTaglibsLastModified(workDir);
function isUpToDate() {
var lastModified = taglibsLastModified.lastModified;
if (lastModified == null) {
return true;
}
var files = require('raptor-files');
var urls = Object.keys(taglibsLastModified.urls);
for (var i = 0, len = urls.length; i < len; i++) {
var url = urls[i];
if (url.startsWith('file://')) {
var taglibFile = files.fromFileUrl(url);
if (!taglibFile.exists() || taglibFile.lastModified() > lastModified) {
return false;
}
}
}
return true;
}
if (!isUpToDate()) {
console.log('One ore more taglibs modified. Removing compiled templates work directory at path "' + workDir.getAbsolutePath() + '"...');
workDir.remove();
}
},
setWorkDir: function (workDir) {
if (workDir) {
logger.debug('Setting work directory to "' + workDir + '"...');
var File = require('raptor-files/File');
if (typeof workDir === 'string') {
workDir = new File(workDir);
}
this._workDir = workDir;
this._taglibsWorkFile = new File(this._workDir, 'taglibs.txt');
this._validateWorkDir(workDir);
} else {
this._workDir = null;
this._taglibsWorkFile = null;
}
},
getWorkDir: function () {
return this._workDir;
}
});