2013-03-24 12:22:21 +00:00
|
|
|
/*\
|
|
|
|
title: $:/plugins/tiddlywiki/filesystem/filesystemadaptor.js
|
|
|
|
type: application/javascript
|
|
|
|
module-type: syncadaptor
|
|
|
|
|
2014-08-14 10:12:25 +00:00
|
|
|
A sync adaptor module for synchronising with the local filesystem via node.js APIs
|
2013-03-24 12:22:21 +00:00
|
|
|
|
|
|
|
\*/
|
|
|
|
(function(){
|
|
|
|
|
|
|
|
/*jslint node: true, browser: true */
|
|
|
|
/*global $tw: false */
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
// Get a reference to the file system
|
2014-12-18 19:52:15 +00:00
|
|
|
var fs = $tw.node ? require("fs") : null,
|
|
|
|
path = $tw.node ? require("path") : null;
|
2013-10-11 21:10:10 +00:00
|
|
|
|
2014-08-14 10:12:25 +00:00
|
|
|
function FileSystemAdaptor(options) {
|
2013-10-11 22:43:51 +00:00
|
|
|
var self = this;
|
2014-08-14 10:12:25 +00:00
|
|
|
this.wiki = options.wiki;
|
2020-06-11 10:36:41 +00:00
|
|
|
this.boot = options.boot || $tw.boot;
|
2017-09-04 13:55:12 +00:00
|
|
|
this.logger = new $tw.utils.Logger("filesystem",{colour: "blue"});
|
2013-12-18 21:11:52 +00:00
|
|
|
// Create the <wiki>/tiddlers folder if it doesn't exist
|
2020-06-11 10:36:41 +00:00
|
|
|
$tw.utils.createDirectory(this.boot.wikiTiddlersPath);
|
2013-03-24 12:22:21 +00:00
|
|
|
}
|
|
|
|
|
2017-02-04 17:25:30 +00:00
|
|
|
FileSystemAdaptor.prototype.name = "filesystem";
|
|
|
|
|
2020-03-30 14:24:05 +00:00
|
|
|
FileSystemAdaptor.prototype.supportsLazyLoading = false;
|
|
|
|
|
2016-07-05 10:29:59 +00:00
|
|
|
FileSystemAdaptor.prototype.isReady = function() {
|
|
|
|
// The file system adaptor is always ready
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2013-03-24 12:22:21 +00:00
|
|
|
FileSystemAdaptor.prototype.getTiddlerInfo = function(tiddler) {
|
2020-11-30 22:31:48 +00:00
|
|
|
//Returns the existing fileInfo for the tiddler. To regenerate, call getTiddlerFileInfo().
|
|
|
|
var title = tiddler.fields.title;
|
|
|
|
return this.boot.files[title];
|
2013-03-24 12:22:21 +00:00
|
|
|
};
|
|
|
|
|
2017-02-11 12:56:42 +00:00
|
|
|
/*
|
|
|
|
Return a fileInfo object for a tiddler, creating it if necessary:
|
|
|
|
filepath: the absolute path to the file containing the tiddler
|
|
|
|
type: the type of the tiddler file (NOT the type of the tiddler -- see below)
|
|
|
|
hasMetaFile: true if the file also has a companion .meta file
|
2013-03-25 10:43:46 +00:00
|
|
|
|
2020-11-30 22:31:48 +00:00
|
|
|
The boot process populates this.boot.files for each of the tiddler files that it loads.
|
|
|
|
The type is found by looking up the extension in $tw.config.fileExtensionInfo (eg "application/x-tiddler" for ".tid" files).
|
2017-02-11 12:56:42 +00:00
|
|
|
|
2020-06-11 10:36:41 +00:00
|
|
|
It is the responsibility of the filesystem adaptor to update this.boot.files for new files that are created.
|
2017-02-11 12:56:42 +00:00
|
|
|
*/
|
2013-03-25 10:43:46 +00:00
|
|
|
FileSystemAdaptor.prototype.getTiddlerFileInfo = function(tiddler,callback) {
|
2020-11-30 22:31:48 +00:00
|
|
|
// Always generate a fileInfo object when this fuction is called
|
2021-03-26 08:39:32 +00:00
|
|
|
var title = tiddler.fields.title, newInfo, pathFilters, extFilters,
|
|
|
|
fileInfo = this.boot.files[title];
|
2021-02-04 16:11:07 +00:00
|
|
|
if(this.wiki.tiddlerExists("$:/config/FileSystemPaths")) {
|
2020-12-06 09:41:03 +00:00
|
|
|
pathFilters = this.wiki.getTiddlerText("$:/config/FileSystemPaths","").split("\n");
|
|
|
|
}
|
2021-02-04 16:11:07 +00:00
|
|
|
if(this.wiki.tiddlerExists("$:/config/FileSystemExtensions")) {
|
2020-12-06 09:41:03 +00:00
|
|
|
extFilters = this.wiki.getTiddlerText("$:/config/FileSystemExtensions","").split("\n");
|
|
|
|
}
|
2020-11-30 22:31:48 +00:00
|
|
|
newInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
|
|
|
|
directory: this.boot.wikiTiddlersPath,
|
2020-12-06 09:41:03 +00:00
|
|
|
pathFilters: pathFilters,
|
|
|
|
extFilters: extFilters,
|
2020-11-30 22:31:48 +00:00
|
|
|
wiki: this.wiki,
|
2021-03-26 08:39:32 +00:00
|
|
|
fileInfo: fileInfo
|
2020-11-30 22:31:48 +00:00
|
|
|
});
|
|
|
|
callback(null,newInfo);
|
2013-03-25 10:43:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-03-24 12:22:21 +00:00
|
|
|
/*
|
|
|
|
Save a tiddler and invoke the callback with (err,adaptorInfo,revision)
|
|
|
|
*/
|
2021-07-05 18:26:20 +00:00
|
|
|
FileSystemAdaptor.prototype.saveTiddler = function(tiddler,callback,options) {
|
2013-10-11 21:10:10 +00:00
|
|
|
var self = this;
|
2021-02-04 16:11:07 +00:00
|
|
|
var syncerInfo = options.tiddlerInfo || {};
|
2013-03-25 10:43:46 +00:00
|
|
|
this.getTiddlerFileInfo(tiddler,function(err,fileInfo) {
|
|
|
|
if(err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
2021-02-04 16:11:07 +00:00
|
|
|
$tw.utils.saveTiddlerToFile(tiddler,fileInfo,function(err,fileInfo) {
|
2020-11-30 22:31:48 +00:00
|
|
|
if(err) {
|
|
|
|
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "open") {
|
2021-02-04 16:11:07 +00:00
|
|
|
fileInfo = fileInfo || self.boot.files[tiddler.fields.title];
|
|
|
|
fileInfo.writeError = true;
|
|
|
|
self.boot.files[tiddler.fields.title] = fileInfo;
|
|
|
|
$tw.syncer.logger.log("Sync failed for \""+tiddler.fields.title+"\" and will be retried with encoded filepath",encodeURIComponent(fileInfo.filepath));
|
2020-11-30 22:31:48 +00:00
|
|
|
return callback(err);
|
|
|
|
} else {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
}
|
2021-02-04 16:11:07 +00:00
|
|
|
// Store new boot info only after successful writes
|
|
|
|
self.boot.files[tiddler.fields.title] = fileInfo;
|
2020-11-30 22:31:48 +00:00
|
|
|
// Cleanup duplicates if the file moved or changed extensions
|
|
|
|
var options = {
|
2021-02-04 16:11:07 +00:00
|
|
|
adaptorInfo: syncerInfo.adaptorInfo || {},
|
|
|
|
bootInfo: fileInfo || {},
|
2020-11-30 22:31:48 +00:00
|
|
|
title: tiddler.fields.title
|
|
|
|
};
|
2021-02-04 16:11:07 +00:00
|
|
|
$tw.utils.cleanupTiddlerFiles(options,function(err,fileInfo) {
|
2020-11-30 22:31:48 +00:00
|
|
|
if(err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
2021-02-04 16:11:07 +00:00
|
|
|
return callback(null,fileInfo);
|
2020-11-30 22:31:48 +00:00
|
|
|
});
|
|
|
|
});
|
2013-03-25 10:43:46 +00:00
|
|
|
});
|
2013-03-24 12:22:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Load a tiddler and invoke the callback with (err,tiddlerFields)
|
2013-12-11 11:45:15 +00:00
|
|
|
|
|
|
|
We don't need to implement loading for the file system adaptor, because all the tiddler files will have been loaded during the boot process.
|
2013-03-24 12:22:21 +00:00
|
|
|
*/
|
2021-07-05 18:26:20 +00:00
|
|
|
FileSystemAdaptor.prototype.loadTiddler = function(title,callback) {
|
2013-12-11 11:45:15 +00:00
|
|
|
callback(null,null);
|
2013-03-24 12:22:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Delete a tiddler and invoke the callback with (err)
|
|
|
|
*/
|
2021-07-05 18:26:20 +00:00
|
|
|
FileSystemAdaptor.prototype.deleteTiddler = function(title,callback,options) {
|
2013-03-25 20:16:12 +00:00
|
|
|
var self = this,
|
2020-06-11 10:36:41 +00:00
|
|
|
fileInfo = this.boot.files[title];
|
2013-03-25 20:16:12 +00:00
|
|
|
// Only delete the tiddler if we have writable information for the file
|
|
|
|
if(fileInfo) {
|
2021-02-04 16:11:07 +00:00
|
|
|
$tw.utils.deleteTiddlerFile(fileInfo,function(err,fileInfo) {
|
2014-02-06 21:36:30 +00:00
|
|
|
if(err) {
|
2020-11-30 22:31:48 +00:00
|
|
|
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
|
|
|
|
// Error deleting the file on disk, should fail gracefully
|
2021-02-04 16:11:07 +00:00
|
|
|
$tw.syncer.displayError("Server desynchronized. Error deleting file for deleted tiddler \"" + title + "\"",err);
|
|
|
|
return callback(null,fileInfo);
|
2020-11-30 22:31:48 +00:00
|
|
|
} else {
|
|
|
|
return callback(err);
|
|
|
|
}
|
2014-02-06 21:36:30 +00:00
|
|
|
}
|
2021-02-04 16:11:07 +00:00
|
|
|
// Remove the tiddler from self.boot.files & return null adaptorInfo
|
2023-03-05 17:40:04 +00:00
|
|
|
self.removeTiddlerFileInfo(title);
|
2021-02-04 16:11:07 +00:00
|
|
|
return callback(null,null);
|
2014-02-06 21:36:30 +00:00
|
|
|
});
|
2013-03-25 20:16:12 +00:00
|
|
|
} else {
|
2021-02-04 16:11:07 +00:00
|
|
|
callback(null,null);
|
2013-03-25 20:16:12 +00:00
|
|
|
}
|
2013-03-24 12:22:21 +00:00
|
|
|
};
|
|
|
|
|
2023-03-03 21:56:40 +00:00
|
|
|
/*
|
|
|
|
Delete a tiddler in cache, without modifying file system.
|
|
|
|
*/
|
2023-03-05 17:40:04 +00:00
|
|
|
FileSystemAdaptor.prototype.removeTiddlerFileInfo = function(title) {
|
|
|
|
// Only delete the tiddler info if we have writable information for the file
|
2023-03-03 21:56:40 +00:00
|
|
|
if(this.boot.files[title]) {
|
|
|
|
delete this.boot.files[title];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2013-03-24 12:22:21 +00:00
|
|
|
if(fs) {
|
|
|
|
exports.adaptorClass = FileSystemAdaptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
})();
|