Add `--build` command
First pass at the build system described in #356. To test it, move to a new, empty directory and try `tiddlywiki editions/tw5.com --verbose --build`
This commit is contained in:
parent
552657fc58
commit
f7e50e0950
|
@ -1,2 +1,3 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
tmp/
|
tmp/
|
||||||
|
output/
|
||||||
|
|
|
@ -1612,6 +1612,7 @@ $tw.boot.startup = function(options) {
|
||||||
wikiThemesSubDir: "./themes",
|
wikiThemesSubDir: "./themes",
|
||||||
wikiLanguagesSubDir: "./languages",
|
wikiLanguagesSubDir: "./languages",
|
||||||
wikiTiddlersSubDir: "./tiddlers",
|
wikiTiddlersSubDir: "./tiddlers",
|
||||||
|
wikiOutputSubDir: "./output",
|
||||||
jsModuleHeaderRegExpString: "^\\/\\*\\\\(?:\\r?\\n)((?:^[^\\r\\n]*(?:\\r?\\n))+?)(^\\\\\\*\\/$(?:\\r?\\n)?)",
|
jsModuleHeaderRegExpString: "^\\/\\*\\\\(?:\\r?\\n)((?:^[^\\r\\n]*(?:\\r?\\n))+?)(^\\\\\\*\\/$(?:\\r?\\n)?)",
|
||||||
fileExtensionInfo: Object.create(null), // Map file extension to {type:}
|
fileExtensionInfo: Object.create(null), // Map file extension to {type:}
|
||||||
contentTypeInfo: Object.create(null) // Map type to {encoding:,extension:}
|
contentTypeInfo: Object.create(null) // Map type to {encoding:,extension:}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
title: $:/language/Help/build
|
||||||
|
description: Automatically run configured commands
|
||||||
|
|
||||||
|
Build the specified build targets for the current wiki. If no build targets are specified then all available targets will be built.
|
||||||
|
|
||||||
|
```
|
||||||
|
--build <target> [<target> ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Build targets are defined in the `tiddlywiki.info` file of a wiki folder.
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
title: $:/language/Help/clearpassword
|
||||||
|
description: Set a password for subsequent crypto operations
|
||||||
|
|
||||||
|
Clear the password for subsequent crypto operations
|
||||||
|
|
||||||
|
```
|
||||||
|
--clearpassword
|
||||||
|
```
|
|
@ -0,0 +1,10 @@
|
||||||
|
title: $:/language/Help/output
|
||||||
|
description: Set the base output directory for subsequent commands
|
||||||
|
|
||||||
|
Sets the base output directory for subsequent commands. The default output directory is the current working directory.
|
||||||
|
|
||||||
|
```
|
||||||
|
--output <pathname>
|
||||||
|
```
|
||||||
|
|
||||||
|
If the specified pathname is relative then it is resolved relative to the current output directory.
|
|
@ -6,3 +6,5 @@ Render an individual tiddler as a specified ContentType, defaults to `text/html`
|
||||||
```
|
```
|
||||||
--rendertiddler <title> <filename> [<type>]
|
--rendertiddler <title> <filename> [<type>]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Any missing directories in the path to the filename are automatically created.
|
||||||
|
|
|
@ -12,3 +12,5 @@ For example:
|
||||||
```
|
```
|
||||||
--rendertiddlers [!is[system]] $:/core/templates/static.tiddler.html ./static text/plain
|
--rendertiddlers [!is[system]] $:/core/templates/static.tiddler.html ./static text/plain
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Any files in the target directory are deleted. The target directory is recursively created if it is missing.
|
||||||
|
|
|
@ -6,3 +6,5 @@ Saves an individual tiddler in its raw text or binary format to the specified fi
|
||||||
```
|
```
|
||||||
--savetiddler <title> <filename>
|
--savetiddler <title> <filename>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Any missing directories in the path to the filename are automatically created.
|
||||||
|
|
|
@ -20,11 +20,20 @@ Parse a sequence of commands
|
||||||
callback: a callback invoked as callback(err) where err is null if there was no error
|
callback: a callback invoked as callback(err) where err is null if there was no error
|
||||||
*/
|
*/
|
||||||
var Commander = function(commandTokens,callback,wiki,streams) {
|
var Commander = function(commandTokens,callback,wiki,streams) {
|
||||||
|
var path = require("path");
|
||||||
this.commandTokens = commandTokens;
|
this.commandTokens = commandTokens;
|
||||||
this.nextToken = 0;
|
this.nextToken = 0;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.wiki = wiki;
|
this.wiki = wiki;
|
||||||
this.streams = streams;
|
this.streams = streams;
|
||||||
|
this.outputPath = process.cwd();
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add a string of tokens to the command queue
|
||||||
|
*/
|
||||||
|
Commander.prototype.addCommandTokens = function(commandTokens) {
|
||||||
|
Array.prototype.push.apply(this.commandTokens,commandTokens);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*\
|
||||||
|
title: $:/core/modules/commands/build.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: command
|
||||||
|
|
||||||
|
Command to build a build target
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
name: "build",
|
||||||
|
synchronous: true
|
||||||
|
};
|
||||||
|
|
||||||
|
var Command = function(params,commander) {
|
||||||
|
this.params = params;
|
||||||
|
this.commander = commander;
|
||||||
|
};
|
||||||
|
|
||||||
|
Command.prototype.execute = function() {
|
||||||
|
// Get the build targets defined in the wiki
|
||||||
|
var buildTargets = $tw.boot.wikiInfo.build;
|
||||||
|
if(!buildTargets) {
|
||||||
|
return "No build targets defined"
|
||||||
|
}
|
||||||
|
// Loop through each of the specified targets
|
||||||
|
var targets;
|
||||||
|
if(this.params.length > 0) {
|
||||||
|
targets = this.params;
|
||||||
|
} else {
|
||||||
|
targets = Object.keys(buildTargets);
|
||||||
|
}
|
||||||
|
for(var targetIndex=0; targetIndex<targets.length; targetIndex++) {
|
||||||
|
var target = targets[targetIndex],
|
||||||
|
commands = buildTargets[target];
|
||||||
|
if(!commands) {
|
||||||
|
return "Build target '" + target + "' not found";
|
||||||
|
}
|
||||||
|
// Add the commands to the queue
|
||||||
|
this.commander.addCommandTokens(commands);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.Command = Command;
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*\
|
||||||
|
title: $:/core/modules/commands/clearpassword.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: command
|
||||||
|
|
||||||
|
Clear password for crypto operations
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
name: "clearpassword",
|
||||||
|
synchronous: true
|
||||||
|
};
|
||||||
|
|
||||||
|
var Command = function(params,commander,callback) {
|
||||||
|
this.params = params;
|
||||||
|
this.commander = commander;
|
||||||
|
this.callback = callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
Command.prototype.execute = function() {
|
||||||
|
$tw.crypto.setPassword(null);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.Command = Command;
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*\
|
||||||
|
title: $:/core/modules/commands/output.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: command
|
||||||
|
|
||||||
|
Command to set the default output location (defaults to current working directory)
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
name: "output",
|
||||||
|
synchronous: true
|
||||||
|
};
|
||||||
|
|
||||||
|
var Command = function(params,commander,callback) {
|
||||||
|
this.params = params;
|
||||||
|
this.commander = commander;
|
||||||
|
this.callback = callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
Command.prototype.execute = function() {
|
||||||
|
var fs = require("fs"),
|
||||||
|
path = require("path");
|
||||||
|
if(this.params.length < 1) {
|
||||||
|
return "Missing output path";
|
||||||
|
}
|
||||||
|
this.commander.outputPath = path.resolve(this.commander.outputPath,this.params[0]);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.Command = Command;
|
||||||
|
|
||||||
|
})();
|
|
@ -31,8 +31,9 @@ Command.prototype.execute = function() {
|
||||||
fs = require("fs"),
|
fs = require("fs"),
|
||||||
path = require("path"),
|
path = require("path"),
|
||||||
title = this.params[0],
|
title = this.params[0],
|
||||||
filename = this.params[1],
|
filename = path.resolve(this.commander.outputPath,this.params[1]),
|
||||||
type = this.params[2] || "text/html";
|
type = this.params[2] || "text/html";
|
||||||
|
$tw.utils.createFileDirectories(filename);
|
||||||
fs.writeFile(filename,this.commander.wiki.renderTiddler(type,title),"utf8",function(err) {
|
fs.writeFile(filename,this.commander.wiki.renderTiddler(type,title),"utf8",function(err) {
|
||||||
self.callback(err);
|
self.callback(err);
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,10 +35,12 @@ Command.prototype.execute = function() {
|
||||||
wiki = this.commander.wiki,
|
wiki = this.commander.wiki,
|
||||||
filter = this.params[0],
|
filter = this.params[0],
|
||||||
template = this.params[1],
|
template = this.params[1],
|
||||||
pathname = this.params[2],
|
pathname = path.resolve(this.commander.outputPath,this.params[2]),
|
||||||
type = this.params[3] || "text/html",
|
type = this.params[3] || "text/html",
|
||||||
extension = this.params[4] || ".html",
|
extension = this.params[4] || ".html",
|
||||||
tiddlers = wiki.filterTiddlers(filter);
|
tiddlers = wiki.filterTiddlers(filter);
|
||||||
|
$tw.utils.deleteDirectory(pathname);
|
||||||
|
$tw.utils.createDirectory(pathname);
|
||||||
$tw.utils.each(tiddlers,function(title) {
|
$tw.utils.each(tiddlers,function(title) {
|
||||||
var parser = wiki.parseTiddler(template),
|
var parser = wiki.parseTiddler(template),
|
||||||
widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title}});
|
widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title}});
|
||||||
|
|
|
@ -31,10 +31,11 @@ Command.prototype.execute = function() {
|
||||||
fs = require("fs"),
|
fs = require("fs"),
|
||||||
path = require("path"),
|
path = require("path"),
|
||||||
title = this.params[0],
|
title = this.params[0],
|
||||||
filename = this.params[1],
|
filename = path.resolve(this.commander.outputPath,this.params[1]),
|
||||||
tiddler = this.commander.wiki.getTiddler(title),
|
tiddler = this.commander.wiki.getTiddler(title),
|
||||||
type = tiddler.fields.type || "text/vnd.tiddlywiki",
|
type = tiddler.fields.type || "text/vnd.tiddlywiki",
|
||||||
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"};
|
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"};
|
||||||
|
$tw.utils.createFileDirectories(filename);
|
||||||
fs.writeFile(filename,tiddler.fields.text,contentTypeInfo.encoding,function(err) {
|
fs.writeFile(filename,tiddler.fields.text,contentTypeInfo.encoding,function(err) {
|
||||||
self.callback(err);
|
self.callback(err);
|
||||||
});
|
});
|
||||||
|
|
|
@ -87,9 +87,13 @@ exports.removeTrailingSeparator = function(dirPath) {
|
||||||
Recursively create a directory
|
Recursively create a directory
|
||||||
*/
|
*/
|
||||||
exports.createDirectory = function(dirPath) {
|
exports.createDirectory = function(dirPath) {
|
||||||
var parts = dirPath.split(path.sep);
|
if(dirPath.substr(dirPath.length-1,1) !== path.sep) {
|
||||||
for(var component=0; component<parts.length; component++) {
|
dirPath = dirPath + path.sep;
|
||||||
var subDirPath = parts.slice(0,component+1).join(path.sep);
|
}
|
||||||
|
var pos = 1;
|
||||||
|
pos = dirPath.indexOf(path.sep,pos);
|
||||||
|
while(pos !== -1) {
|
||||||
|
var subDirPath = dirPath.substr(0,pos);
|
||||||
if(!$tw.utils.isDirectory(subDirPath)) {
|
if(!$tw.utils.isDirectory(subDirPath)) {
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(subDirPath);
|
fs.mkdirSync(subDirPath);
|
||||||
|
@ -97,6 +101,33 @@ exports.createDirectory = function(dirPath) {
|
||||||
return "Error creating directory '" + subDirPath + "'";
|
return "Error creating directory '" + subDirPath + "'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pos = dirPath.indexOf(path.sep,pos + 1);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Recursively create directories needed to contain a specified file
|
||||||
|
*/
|
||||||
|
exports.createFileDirectories = function(filePath) {
|
||||||
|
return $tw.utils.createDirectory(path.dirname(filePath));
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Recursively delete a directory
|
||||||
|
*/
|
||||||
|
exports.deleteDirectory = function(dirPath) {
|
||||||
|
if(fs.existsSync(dirPath)) {
|
||||||
|
var entries = fs.readdirSync(dirPath);
|
||||||
|
for(var entryIndex=0; entryIndex<entries.length; entryIndex++) {
|
||||||
|
var currPath = dirPath + path.sep + entries[entryIndex];
|
||||||
|
if(fs.lstatSync(currPath).isDirectory()) {
|
||||||
|
$tw.utils.deleteDirectory(currPath);
|
||||||
|
} else {
|
||||||
|
fs.unlinkSync(currPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fs.rmdirSync(dirPath);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
created: 20140425085548209
|
||||||
|
modified: 20140425085738745
|
||||||
|
tags: command
|
||||||
|
title: BuildCommand
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
{{$:/language/Help/build}}
|
|
@ -0,0 +1,4 @@
|
||||||
|
title: ClearPasswordCommand
|
||||||
|
tags: command
|
||||||
|
|
||||||
|
{{$:/language/Help/clearpassword}}
|
|
@ -0,0 +1,7 @@
|
||||||
|
created: 20140425085548209
|
||||||
|
modified: 20140425085738745
|
||||||
|
tags: command
|
||||||
|
title: OutputCommand
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
{{$:/language/Help/output}}
|
|
@ -24,6 +24,7 @@ The `tiddlywiki.info` file in a wiki folder contains a JSON object comprising th
|
||||||
* ''themes'' - an array of theme names to be included in the wiki
|
* ''themes'' - an array of theme names to be included in the wiki
|
||||||
* ''languages'' - an array of language names to be included in the wiki
|
* ''languages'' - an array of language names to be included in the wiki
|
||||||
* ''includeWikis'' - an array of relative paths to external wiki folders to be included in the wiki
|
* ''includeWikis'' - an array of relative paths to external wiki folders to be included in the wiki
|
||||||
|
* ''build'' - a hashmap of named build targets, each defined by an array of command tokens (see BuildCommand)
|
||||||
* ''config'' - an optional hashmap of configuration options (see below)
|
* ''config'' - an optional hashmap of configuration options (see below)
|
||||||
|
|
||||||
Configuration options include:
|
Configuration options include:
|
||||||
|
@ -34,16 +35,23 @@ For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"tiddlywiki/tiddlyweb",
|
"tiddlywiki/tiddlyweb",
|
||||||
"tiddlywiki/filesystem"
|
"tiddlywiki/filesystem"
|
||||||
],
|
],
|
||||||
"includeWikis": [
|
"includeWikis": [
|
||||||
"../tw5.com"
|
"../tw5.com"
|
||||||
],
|
],
|
||||||
"config": {
|
"build": {
|
||||||
"retain-original-tiddler-path": true
|
"index": [
|
||||||
}
|
"--rendertiddler","$:/core/save/all","index.html","text/plain"],
|
||||||
|
"favicon": [
|
||||||
|
"--savetiddler","$:/favicon.ico","favicon.ico",
|
||||||
|
"--savetiddler","$:/green_favicon.ico","static/favicon.ico"]
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"retain-original-tiddler-path": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -55,26 +63,26 @@ Sub-folders within the `tiddlers` folder can also be given a `tiddlywiki.files`
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"tiddlers": [
|
"tiddlers": [
|
||||||
{
|
{
|
||||||
"file": "d3.min.js",
|
"file": "d3.min.js",
|
||||||
"fields": {
|
"fields": {
|
||||||
"type": "application/javascript",
|
"type": "application/javascript",
|
||||||
"title": "$:/plugins/tiddlywiki/d3/d3.js",
|
"title": "$:/plugins/tiddlywiki/d3/d3.js",
|
||||||
"module-type": "library"
|
"module-type": "library"
|
||||||
},
|
},
|
||||||
"prefix": "var d3;if($tw.browser){\n",
|
"prefix": "var d3;if($tw.browser){\n",
|
||||||
"suffix": "}\nexports.d3 = d3;\n"
|
"suffix": "}\nexports.d3 = d3;\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file": "cloud/d3.layout.cloud.js",
|
"file": "cloud/d3.layout.cloud.js",
|
||||||
"fields": {
|
"fields": {
|
||||||
"type": "application/javascript",
|
"type": "application/javascript",
|
||||||
"title": "$:/plugins/tiddlywiki/d3/d3.layout.cloud.js",
|
"title": "$:/plugins/tiddlywiki/d3/d3.layout.cloud.js",
|
||||||
"module-type": "library"
|
"module-type": "library"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,30 @@
|
||||||
"zh-Hant",
|
"zh-Hant",
|
||||||
"it-IT",
|
"it-IT",
|
||||||
"ja-JP"
|
"ja-JP"
|
||||||
]
|
],
|
||||||
,
|
"build": {
|
||||||
|
"index": [
|
||||||
|
"--rendertiddler","$:/core/save/all","index.html","text/plain"],
|
||||||
|
"encrypted": [
|
||||||
|
"--password", "password",
|
||||||
|
"--rendertiddler", "$:/core/save/all", "encrypted.html", "text/plain",
|
||||||
|
"--clearpassword"],
|
||||||
|
"favicon": [
|
||||||
|
"--savetiddler","$:/favicon.ico","favicon.ico",
|
||||||
|
"--savetiddler","$:/green_favicon.ico","static/favicon.ico"],
|
||||||
|
"readmes": [
|
||||||
|
"--rendertiddler","ReadMe","readme.md","text/html",
|
||||||
|
"--rendertiddler","ContributingTemplate","contributing.md","text/html",
|
||||||
|
"--rendertiddler","$:/core/copyright.txt","licenses/copyright.md","text/html"],
|
||||||
|
"empty": [
|
||||||
|
"--rendertiddler","$:/editions/tw5.com/download-empty","empty.html","text/plain",
|
||||||
|
"--rendertiddler","$:/editions/tw5.com/download-empty","empty.hta","text/plain"],
|
||||||
|
"static": [
|
||||||
|
"--rendertiddler","$:/core/templates/static.template.html","static.html","text/plain",
|
||||||
|
"--rendertiddler","$:/core/templates/alltiddlers.template.html","alltiddlers.html","text/plain",
|
||||||
|
"--rendertiddler","$:/core/templates/static.template.css","static/static.css","text/plain",
|
||||||
|
"--rendertiddlers","[!is[system]]","$:/core/templates/static.tiddler.html","static","text/plain"]
|
||||||
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"retain-original-tiddler-path": true
|
"retain-original-tiddler-path": true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue