Fix filesystem regression (#5176)

* $:/config/OriginalTiddlerPaths if no filters match

* fixed & docs updated

* tested with tiddlywiki.files & tw.com edition

* typos

* originalpath to options, propigate isEditableFile

* syntax cleanup
This commit is contained in:
Joshua Fontany 2020-12-02 01:47:51 -08:00 committed by GitHub
parent c3055f92a9
commit c6bb783308
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 34 deletions

View File

@ -1894,7 +1894,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
});
});
if(isEditableFile) {
tiddlers.push({filepath: pathname, hasMetaFile: !!metadata && !isTiddlerFile, tiddlers: fileTiddlers});
tiddlers.push({filepath: pathname, hasMetaFile: !!metadata && !isTiddlerFile, isEditableFile: true, tiddlers: fileTiddlers});
} else {
tiddlers.push({tiddlers: fileTiddlers});
}
@ -2074,6 +2074,11 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
} else {
return null;
}
// Save the path to the tiddlers folder for the filesystemadaptor
var config = wikiInfo.config || {};
if($tw.boot.wikiPath == wikiPath) {
$tw.boot.wikiTiddlersPath = path.resolve($tw.boot.wikiPath,config["default-tiddler-location"] || $tw.config.wikiTiddlersSubDir);
}
// Load any parent wikis
if(wikiInfo.includeWikis) {
parentPaths = parentPaths.slice(0);
@ -2107,27 +2112,30 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
$tw.boot.files[tiddler.title] = {
filepath: tiddlerFile.filepath,
type: tiddlerFile.type,
hasMetaFile: tiddlerFile.hasMetaFile
hasMetaFile: tiddlerFile.hasMetaFile,
isEditableFile: config["retain-original-tiddler-path"] || tiddlerFile.isEditableFile || tiddlerFile.filepath.indexOf($tw.boot.wikiTiddlersPath) !== 0
};
});
}
$tw.wiki.addTiddlers(tiddlerFile.tiddlers);
});
// Save the original tiddler file locations if requested
var config = wikiInfo.config || {};
if(config["retain-original-tiddler-path"]) {
var output = {}, relativePath;
if ($tw.boot.wikiPath == wikiPath) {
// Save the original tiddler file locations if requested
var output = {}, relativePath, fileInfo;
for(var title in $tw.boot.files) {
relativePath = path.relative(resolvedWikiPath,$tw.boot.files[title].filepath);
output[title] =
path.sep === "/" ?
relativePath :
relativePath.split(path.sep).join("/");
fileInfo = $tw.boot.files[title];
if(fileInfo.isEditableFile) {
relativePath = path.relative($tw.boot.wikiTiddlersPath,fileInfo.filepath);
output[title] =
path.sep === "/" ?
relativePath :
relativePath.split(path.sep).join("/");
}
}
if(Object.keys(output).length > 0){
$tw.wiki.addTiddler({title: "$:/config/OriginalTiddlerPaths", type: "application/json", text: JSON.stringify(output)});
}
$tw.wiki.addTiddler({title: "$:/config/OriginalTiddlerPaths", type: "application/json", text: JSON.stringify(output)});
}
// Save the path to the tiddlers folder for the filesystemadaptor
$tw.boot.wikiTiddlersPath = path.resolve($tw.boot.wikiPath,config["default-tiddler-location"] || $tw.config.wikiTiddlersSubDir);
// Load any plugins within the wiki folder
var wikiPluginsPath = path.resolve(wikiPath,$tw.config.wikiPluginsSubDir);
if(fs.existsSync(wikiPluginsPath)) {
@ -2174,7 +2182,7 @@ $tw.loadTiddlersNode = function() {
// Load any extra plugins
$tw.utils.each($tw.boot.extraPlugins,function(name) {
if(name.charAt(0) === "+") { // Relative path to plugin
var pluginFields = $tw.loadPluginFolder(name.substring(1));;
var pluginFields = $tw.loadPluginFolder(name.substring(1));
if(pluginFields) {
$tw.wiki.addTiddler(pluginFields);
}

View File

@ -206,12 +206,14 @@ Create a fileInfo object for saving a tiddler:
filepath: the absolute path to the file containing the tiddler
type: the type of the tiddler file on disk (NOT the type of the tiddler)
hasMetaFile: true if the file also has a companion .meta file
isEditableFile: true if the tiddler was loaded via non-standard options & marked editable
Options include:
directory: absolute path of root directory to which we are saving
pathFilters: optional array of filters to be used to generate the base path
extFilters: optional array of filters to be used to generate the base path
wiki: optional wiki for evaluating the pathFilters,
fileInfo: an existing fileInfo to check against
originalpath: a preferred filepath if no pathFilters match
*/
exports.generateTiddlerFileInfo = function(tiddler,options) {
var fileInfo = {}, metaExt;
@ -271,8 +273,13 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
directory: options.directory,
pathFilters: options.pathFilters,
wiki: options.wiki,
fileInfo: options.fileInfo
fileInfo: options.fileInfo,
originalpath: options.originalpath
});
// Propigate the isEditableFile flag
if(options.fileInfo) {
fileInfo.isEditableFile = options.fileInfo.isEditableFile || false;
}
return fileInfo;
};
@ -313,6 +320,7 @@ exports.generateTiddlerFilepath = function(title,options) {
var self = this,
directory = options.directory || "",
extension = options.extension || "",
originalpath = options.originalpath || "",
filepath;
// Check if any of the pathFilters applies
if(options.pathFilters && options.wiki) {
@ -326,7 +334,11 @@ exports.generateTiddlerFilepath = function(title,options) {
}
});
}
if(!filepath) {
if(!filepath && originalpath !== "") {
//Use the originalpath without the extension
var ext = path.extname(originalpath);
filepath = originalpath.substring(0,originalpath.length - ext.length);;
} else if(!filepath) {
filepath = title;
// If the filepath already ends in the extension then remove it
if(filepath.substring(filepath.length - extension.length) === extension) {
@ -367,8 +379,8 @@ exports.generateTiddlerFilepath = function(title,options) {
}
count++;
} while(fs.existsSync(fullPath));
//If the path does not start with the wiki directory, or if the last write failed
var encode = fullPath.indexOf($tw.boot.wikiPath) !== 0 || ((options.fileInfo || {writeError: false}).writeError == true);
//If the path does not start with the wikiPath directory or the wikiTiddlersPath directory, or if the last write failed
var encode = !(fullPath.indexOf($tw.boot.wikiPath) == 0 || fullPath.indexOf($tw.boot.wikiTiddlersPath) == 0) || ((options.fileInfo || {writeError: false}).writeError == true);
if(encode){
//encodeURIComponent() and then resolve to tiddler directory
fullPath = path.resolve(directory, encodeURIComponent(fullPath));

View File

@ -4,13 +4,15 @@ tags: [[TiddlyWiki on Node.js]]
title: Customising Tiddler File Naming
type: text/vnd.tiddlywiki
By default, a [[TiddlyWiki on Node.js]] instance using a [[wiki folder|TiddlyWikiFolders]] will create new tiddler files by using the sanitised and disambiguated title as filename and write them to the wiki folder's `tiddlers/` directory. The default file extension of `.tid` is used for tiddlers that are missing the `type` field, or for tiddlers of type "text/vnd.tiddlywiki". Tidders of other types are saved according to their IMIE types (defined at boot startup). Both the logical path (directory and file name) and the file extension can be customized independently by creating optional tiddlers: [[$:/config/FileSystemPaths]] and [[$:/config/FileSystemExtensions]].
By default, a [[TiddlyWiki on Node.js]] instance using a [[wiki folder|TiddlyWikiFolders]] will create new tiddler files by using the sanitised and disambiguated title as filename and write them to the wiki folder's `tiddlers/` directory. This can be overridden by mapping a path in the wiki's tiddlywiki.info file, using a `default-tiddler-location` property in the `config` object. All filepath operations are relative to this `$tw.boot.wikiTiddlersPath` internal javacript variable.
The default file extension of `.tid` is used for tiddlers that are missing the `type` field, or for tiddlers of type "text/vnd.tiddlywiki". Tidders of other types are saved according to their IMIE types (defined at boot startup). Both the logical path (directory and file name) and the file extension can be customized independently by creating optional tiddlers: [[$:/config/FileSystemPaths]] and [[$:/config/FileSystemExtensions]].
! File System Paths
The logical path can be customised by creating a tiddler [[$:/config/FileSystemPaths]] containing one or more [[filter expressions|Filter Syntax]], each on a line of its own. Newly created tiddlers are matched to each filter in turn, and the first output of the first filter to produce any output is taken as a logical path to be used for the tiddler file. Tiddlers are also tested against the [[$:/config/FileSystemPaths]] on every save to disk, and if the logical path has changed a new file is created and the old file deleted.
Tiddlers are limited to being written to the [[wiki folder|TiddlyWikiFolders]]. Any error saving a tiddler to disk, with a logical path that does not start with the wiki folder's path the most common error, causes the filepath to be encoded via Javascript's `encodeURIComponent()` method and the tiddler is saved as this file in the wiki folder's `tiddlers/` directory.
Tiddlers are limited to being written to the [[wiki folder|TiddlyWikiFolders]]. Any error saving a tiddler to disk, with a logical path that does not start with the wiki folder's path the most common error, causes the filepath to be encoded via Javascript's `encodeURIComponent()` method and the tiddler is saved as this file in the wiki folder's `$tw.boot.wikiTiddlersPath` directory.
Logical paths do not include the file-on-disk's extension (see below), and they can use `/` or `\` as directory separator (when generating the physical path, this is replaced by the correct separator for the platform ~TiddlyWiki is running on). If none of the filters matches, the logical path is simply the title with all occurences of `/` replaced by `_` (for backwards compatibility).
@ -22,13 +24,12 @@ In both cases, the characters `<>~:"\|?*^` are replaced by `_` in order to guara
[is[system]!has[draft.of]removeprefix[$:/]addprefix[_system/]]
[is[draft]search-replace:g:regexp[/|\\],[_]addprefix[drafts/]]
[tag[task]addprefix[mytasks/]]
[tag[externalnote]addprefix[../externalnotes/]]
[addprefix[wiki/]]
[!tag[externalnote]addprefix[wiki/]]
```
This will store newly created system tiddlers that are not drafts of other tiddlers in `tiddlers/_system` (after stripping the `$:/` prefix). Next, all drafts have the path seperator characters in their titles replaced by "_" and are stored in `tiddlers/drafts/`. Then tiddlers tagged [[task]] are stored in a subdirectory `tiddlers/mytasks/`. Next, all tiddlers tagged "externalnote" will be written to `<wikiFolder>/tiddlers/../externalnotes/`, which resolves to `<wikiFolder>/externalnotes/` and places these tiddlers outside of the tiddler folder. Use [[tiddlywiki.files Files|tiddlywiki.files_Files]] to reimport these tiddlers when the wiki server is restarted. Finally, all tidders will match the final `[addprefix[wiki/]]` storing these in `<wikiFolder>/tiddlers/wiki/`.
This will store newly created system tiddlers that are not drafts of other tiddlers in `tiddlers/_system` (after stripping the `$:/` prefix). Next, all drafts have the path seperator characters in their titles replaced by "_" and are stored in `tiddlers/drafts/`. Then tiddlers tagged [[task]] are stored in a subdirectory `tiddlers/mytasks/`. Finally, all tidders not tagged with "externalnote" will match the final `[!tag[externalnote]addprefix[wiki/]]` storing these in `/wiki/`. In this example, tiddlers tagged with "externalnote" have been imported using [[tiddlywiki.files Files|tiddlywiki.files_Files]] with an "isEditableFile" flag set to true, causing the server to remember their original file path.
Because there was a filter match, any `/` or `\` in the tiddler title is mapped to a path separator. With the above filters, the non-system, non-draft tiddler `some/thing/entirely/new` (with no tags) will be saved to `<wikiFolder>/tiddlers/wiki/some/thing/entirely/new.tid` (ie, the file `new.tid` in a directory called `entirely/`). Thus, $:/config/FileSystemPaths itself will end up in `tiddlers/_system/config/FileSystemPaths.tid` or `tiddlers\_system\config\FileSystemPaths.tid`, depending on the platform.
Whenever a tiddler generates a $:/config/FileSystemPaths filter match, any `/` or `\` in the tiddler title is mapped to a path separator. With the above filters, the non-system, non-draft tiddler `some/thing/entirely/new` (with no tags) will be saved to `<wikiFolder>/tiddlers/wiki/some/thing/entirely/new.tid` (ie, the file `new.tid` in a directory called `entirely/`). Thus, $:/config/FileSystemPaths itself will end up in `tiddlers/_system/config/FileSystemPaths.tid` or `tiddlers\_system\config\FileSystemPaths.tid`, depending on the platform.
! File System Extensions

View File

@ -51,7 +51,7 @@ Directory specifications in the `directories` array may take the following forms
** ''path'' - (required) the absolute or relative path to the directory containing the tiddler files (relative paths are interpreted relative to the path of the `tiddlywiki.files` file). Note that the directory is not recursively searched; sub-directories are ignored
** ''filesRegExp'' - (optional) a [[regular expression|https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions]] that matches the filenames of the files that should be processed within the directory
** ''isTiddlerFile'' - (required) if `true`, the file will be treated as a [[tiddler file|TiddlerFiles]] and deserialised to extract the tiddlers. Otherwise, the raw content of the file is assigned to the `text` field without any parsing
** ''isEditableFile'' - (optional) if `true`, changes to the tiddler be saved back to the original file. The ''path'' of the current directory being read must be within the wiki's base directory, and a $:/config/FileSystemPath filter is required to add the correct logical path to the tiddler's title (see second **Example**). <<.from-version "5.1.23">>
** ''isEditableFile'' - (optional) if `true`, changes to the tiddler be saved back to the original file. The tiddler will be saved back to the original filepath as long as it does not generate a result from the $:/config/FileSystemPath filters, which will override the final filepath generated if a result is returned from a filter. <<.from-version "5.1.23">>
** ''fields'' - (required) an object containing values that override or customise the fields provided in the tiddler file (see above)
Fields can be overridden for particular files by creating a file with the same name plus the suffix `.meta` -- see TiddlerFiles.
@ -102,7 +102,7 @@ This example retrieves all the files with the extension `.txt` from a folder spe
* ''created'' - set to the creation date/time of the text file
* ''modified'' - set to the modification date/time of the text file
* ''type'' - set to `text/plain`
* ''tags'' - set to `[[note]] [[externalnote]]` (using array notation)
* ''tags'' - set to `[[note]] [[externalnote]] [[.txt]]` (using array notation)
* ''text'' - not set, thus the content of the file is loaded as the text field
```
@ -125,8 +125,8 @@ This example retrieves all the files with the extension `.txt` from a folder spe
}
```
This will load all text files in the `<wikiBase>/externalnotes/` directory into the wiki as individual tiddlers. These can be a collection of snippets in various markup-languages. Then, the `type` field of each of these tiddlers can be changed to match their languages For example, "text/vnd.tiddlywiki" for wikitext, or "text/markdown" for markdown files. Then, using $:/config/FileSystemPaths and $:/config/FileSystemExtentions tiddlers with the following lines we can cause any changes to these tiddlers to be saved back to the directory they started from, and as "*.txt" files with accompanying "*.txt.meta" files. These meta files will then over-ride any fields generated from the config `tiddlywiki.files` file (such as the tiddler's `type` field) when the server is restarted.
This will load all text files in the `../../externalnotes/` directory into the wiki as individual tiddlers. These can be a collection of snippets in various markup-languages. Then, the `type` field of each of these tiddlers can be changed to match their languages For example, "text/vnd.tiddlywiki" for wikitext, or "text/markdown" for markdown files. Then, using $:/config/FileSystemPaths and $:/config/FileSystemExtentions tiddlers with the following lines we can cause any changes to these tiddlers to be saved back to the directory they started from, and also as "*.txt" files with accompanying "*.txt.meta" files. These meta files will be generated as required, and will then over-ride any fields generated from the config `tiddlywiki.files` file (such as the tiddler's `type` field) when the server is restarted.
From the examples in [[Customising Tiddler File Naming]] we see that the `[tag[externalnote]addprefix[../externalnotes/]]` filter in the $:/config/FileSystemPaths tiddler catches all tiddlers tagged with `externalnotes` (that have not matched an earlier filter). These tiddlers have "../externalnotes/" appended to their titles to render the final logical path. As this path starts in the wiki's "tiddlers/" folder by default (one folder above the folder holding the above config file) it differes by one set of "../".
From the examples in [[Customising Tiddler File Naming]] we see that the final `[!tag[externalnote]addprefix[wiki/]]` filter in the $:/config/FileSystemPaths tiddler excludes all tiddlers tagged with `externalnotes` (that have not matched an earlier filter). These tiddlers have their filepath retrieved from the $:/config/OriginalTiddlerPaths generated upon boot startup.
Then, the `[tag[.txt]then[.txt]]` filter in the $:/config/FileSystemExtensions tiddler forces all these text files (which start with tag ".txt") to be saved back to disk as *.txt and accompanying *.txt.meta files (overriding the normal tiddler-type to file-type mapping). In this case, allowing the snippets of Tiddlywiki wikitext or markdown-text to be saved back to "text" *.txt files.
Then, the `[tag[.txt]then[.txt]]` filter in the $:/config/FileSystemExtensions tiddler forces all these tiddlers to be saved back to disk as *.txt and accompanying *.txt.meta files (overriding the normal tiddler-type to file-type mapping). In this case, allowing the snippets of Tiddlywiki wikitext or markdown-text to be saved back to "text" *.txt files.

View File

@ -52,16 +52,15 @@ The type is found by looking up the extension in $tw.config.fileExtensionInfo (e
It is the responsibility of the filesystem adaptor to update this.boot.files for new files that are created.
*/
FileSystemAdaptor.prototype.getTiddlerFileInfo = function(tiddler,callback) {
// See if we've already got information about this file
var title = tiddler.fields.title,
newInfo, fileInfo = this.boot.files[title];
// Always generate a fileInfo object when this fuction is called
var title = tiddler.fields.title, newInfo;
newInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
directory: this.boot.wikiTiddlersPath,
pathFilters: this.wiki.getTiddlerText("$:/config/FileSystemPaths","").split("\n"),
extFilters: this.wiki.getTiddlerText("$:/config/FileSystemExtensions","").split("\n"),
wiki: this.wiki,
fileInfo: fileInfo
fileInfo: this.boot.files[title],
originalpath: this.wiki.extractTiddlerDataItem("$:/config/OriginalTiddlerPaths",title, "")
});
this.boot.files[title] = newInfo;
callback(null,newInfo);