mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-27 03:57:21 +00:00
Fix filesystem (#5465)
This commit is contained in:
parent
9f9ce6595b
commit
bfa062f23d
@ -158,11 +158,25 @@ WikiFolderMaker.prototype.saveCustomPlugin = function(pluginTiddler) {
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.saveTiddler = function(directory,tiddler) {
|
||||
var title = tiddler.fields.title, fileInfo, pathFilters, extFilters;
|
||||
if(this.wiki.tiddlerExists("$:/config/FileSystemPaths")) {
|
||||
pathFilters = this.wiki.getTiddlerText("$:/config/FileSystemPaths","").split("\n");
|
||||
}
|
||||
if(this.wiki.tiddlerExists("$:/config/FileSystemExtensions")) {
|
||||
extFilters = this.wiki.getTiddlerText("$:/config/FileSystemExtensions","").split("\n");
|
||||
}
|
||||
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
|
||||
directory: path.resolve(this.wikiFolderPath,directory),
|
||||
wiki: this.wiki
|
||||
wiki: this.wiki,
|
||||
pathFilters: pathFilters,
|
||||
extFilters: extFilters,
|
||||
originalpath: this.wiki.extractTiddlerDataItem("$:/config/OriginalTiddlerPaths",title, "")
|
||||
});
|
||||
try {
|
||||
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
|
||||
} catch (err) {
|
||||
console.log("SaveWikiFolder: Error saving file '" + fileInfo.filepath + "', tiddler: '" + tiddler.fields.title);
|
||||
}
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.saveJSONFile = function(filename,json) {
|
||||
|
@ -640,10 +640,6 @@ DeleteTiddlerTask.prototype.run = function(callback) {
|
||||
}
|
||||
// Remove the info stored about this tiddler
|
||||
delete self.syncer.tiddlerInfo[self.title];
|
||||
if($tw.boot.files){
|
||||
// Remove the tiddler from $tw.boot.files
|
||||
delete $tw.boot.files[self.title];
|
||||
}
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
|
@ -252,7 +252,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
extFilters: options.extFilters,
|
||||
wiki: options.wiki
|
||||
});
|
||||
if(metaExt){
|
||||
if(metaExt) {
|
||||
if(metaExt === ".tid") {
|
||||
// Overriding to the .tid extension needs special handling
|
||||
fileInfo.type = "application/x-tiddler";
|
||||
@ -388,20 +388,18 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
// If the last write failed with an error, or if path does not start with:
|
||||
// the resolved options.directory, the resolved wikiPath directory, or the wikiTiddlersPath directory,
|
||||
// then encodeURIComponent() and resolve to tiddler directory
|
||||
var newPath = fullPath,
|
||||
var writePath = $tw.hooks.invokeHook("th-make-tiddler-path",fullPath),
|
||||
encode = (options.fileInfo || {writeError: false}).writeError == true;
|
||||
if(!encode){
|
||||
if(!encode) {
|
||||
encode = !(fullPath.indexOf(path.resolve(directory)) == 0 ||
|
||||
fullPath.indexOf(path.resolve($tw.boot.wikiPath)) == 0 ||
|
||||
fullPath.indexOf($tw.boot.wikiTiddlersPath) == 0);
|
||||
}
|
||||
if(encode){
|
||||
fullPath = path.resolve(directory, encodeURIComponent(fullPath));
|
||||
if(encode) {
|
||||
writePath = path.resolve(directory,encodeURIComponent(fullPath));
|
||||
}
|
||||
// Call hook to allow plugins to modify the final path
|
||||
fullPath = $tw.hooks.invokeHook("th-make-tiddler-path", newPath, fullPath);
|
||||
// Return the full path to the file
|
||||
return fullPath;
|
||||
return writePath;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -419,14 +417,29 @@ exports.saveTiddlerToFile = function(tiddler,fileInfo,callback) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
fs.writeFile(fileInfo.filepath + ".meta",tiddler.getFieldStringBlock({exclude: ["text","bag"]}),"utf8",callback);
|
||||
fs.writeFile(fileInfo.filepath + ".meta",tiddler.getFieldStringBlock({exclude: ["text","bag"]}),"utf8",function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null,fileInfo);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Save the tiddler as a self contained templated file
|
||||
if(fileInfo.type === "application/x-tiddler") {
|
||||
fs.writeFile(fileInfo.filepath,tiddler.getFieldStringBlock({exclude: ["text","bag"]}) + (!!tiddler.fields.text ? "\n\n" + tiddler.fields.text : ""),"utf8",callback);
|
||||
fs.writeFile(fileInfo.filepath,tiddler.getFieldStringBlock({exclude: ["text","bag"]}) + (!!tiddler.fields.text ? "\n\n" + tiddler.fields.text : ""),"utf8",function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null,fileInfo);
|
||||
});
|
||||
} else {
|
||||
fs.writeFile(fileInfo.filepath,JSON.stringify([tiddler.getFieldStrings({exclude: ["bag"]})],null,$tw.config.preferences.jsonSpaces),"utf8",callback);
|
||||
fs.writeFile(fileInfo.filepath,JSON.stringify([tiddler.getFieldStrings({exclude: ["bag"]})],null,$tw.config.preferences.jsonSpaces),"utf8",function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null,fileInfo);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -457,10 +470,12 @@ exports.saveTiddlerToFileSync = function(tiddler,fileInfo) {
|
||||
/*
|
||||
Delete a file described by the fileInfo if it exits
|
||||
*/
|
||||
exports.deleteTiddlerFile = function(fileInfo, callback) {
|
||||
exports.deleteTiddlerFile = function(fileInfo,callback) {
|
||||
//Only attempt to delete files that exist on disk
|
||||
if(!fileInfo.filepath || !fs.existsSync(fileInfo.filepath)) {
|
||||
return callback(null);
|
||||
//For some reason, the tiddler is only in memory or we can't modify the file at this path
|
||||
$tw.syncer.displayError("Server deleteTiddlerFile task failed for filepath: "+fileInfo.filepath);
|
||||
return callback(null,fileInfo);
|
||||
}
|
||||
// Delete the file
|
||||
fs.unlink(fileInfo.filepath,function(err) {
|
||||
@ -473,10 +488,20 @@ exports.deleteTiddlerFile = function(fileInfo, callback) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return $tw.utils.deleteEmptyDirs(path.dirname(fileInfo.filepath),callback);
|
||||
return $tw.utils.deleteEmptyDirs(path.dirname(fileInfo.filepath),function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null,fileInfo);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return $tw.utils.deleteEmptyDirs(path.dirname(fileInfo.filepath),callback);
|
||||
return $tw.utils.deleteEmptyDirs(path.dirname(fileInfo.filepath),function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null,fileInfo);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -486,25 +511,25 @@ Cleanup old files on disk, by comparing the options values:
|
||||
adaptorInfo from $tw.syncer.tiddlerInfo
|
||||
bootInfo from $tw.boot.files
|
||||
*/
|
||||
exports.cleanupTiddlerFiles = function(options, callback) {
|
||||
exports.cleanupTiddlerFiles = function(options,callback) {
|
||||
var adaptorInfo = options.adaptorInfo || {},
|
||||
bootInfo = options.bootInfo || {},
|
||||
title = options.title || "undefined";
|
||||
if(adaptorInfo.filepath && bootInfo.filepath && adaptorInfo.filepath !== bootInfo.filepath) {
|
||||
return $tw.utils.deleteTiddlerFile(adaptorInfo, function(err){
|
||||
$tw.utils.deleteTiddlerFile(adaptorInfo,function(err) {
|
||||
if(err) {
|
||||
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
|
||||
// Error deleting the previous file on disk, should fail gracefully
|
||||
$tw.syncer.displayError("Server desynchronized. Error cleaning up previous file for tiddler: "+title, err);
|
||||
return callback(null);
|
||||
$tw.syncer.displayError("Server desynchronized. Error cleaning up previous file for tiddler: \""+title+"\"",err);
|
||||
return callback(null,bootInfo);
|
||||
} else {
|
||||
return callback(err);
|
||||
}
|
||||
}
|
||||
return callback(null);
|
||||
return callback(null,bootInfo);
|
||||
});
|
||||
} else {
|
||||
return callback(null);
|
||||
return callback(null,bootInfo);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -54,10 +54,10 @@ It is the responsibility of the filesystem adaptor to update this.boot.files for
|
||||
FileSystemAdaptor.prototype.getTiddlerFileInfo = function(tiddler,callback) {
|
||||
// Always generate a fileInfo object when this fuction is called
|
||||
var title = tiddler.fields.title, newInfo, pathFilters, extFilters;
|
||||
if(this.wiki.tiddlerExists("$:/config/FileSystemPaths")){
|
||||
if(this.wiki.tiddlerExists("$:/config/FileSystemPaths")) {
|
||||
pathFilters = this.wiki.getTiddlerText("$:/config/FileSystemPaths","").split("\n");
|
||||
}
|
||||
if(this.wiki.tiddlerExists("$:/config/FileSystemExtensions")){
|
||||
if(this.wiki.tiddlerExists("$:/config/FileSystemExtensions")) {
|
||||
extFilters = this.wiki.getTiddlerText("$:/config/FileSystemExtensions","").split("\n");
|
||||
}
|
||||
newInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
|
||||
@ -66,9 +66,8 @@ FileSystemAdaptor.prototype.getTiddlerFileInfo = function(tiddler,callback) {
|
||||
extFilters: extFilters,
|
||||
wiki: this.wiki,
|
||||
fileInfo: this.boot.files[title],
|
||||
originalpath: this.wiki.extractTiddlerDataItem("$:/config/OriginalTiddlerPaths",title, "")
|
||||
originalpath: this.wiki.extractTiddlerDataItem("$:/config/OriginalTiddlerPaths",title,"")
|
||||
});
|
||||
this.boot.files[title] = newInfo;
|
||||
callback(null,newInfo);
|
||||
};
|
||||
|
||||
@ -76,35 +75,38 @@ FileSystemAdaptor.prototype.getTiddlerFileInfo = function(tiddler,callback) {
|
||||
/*
|
||||
Save a tiddler and invoke the callback with (err,adaptorInfo,revision)
|
||||
*/
|
||||
FileSystemAdaptor.prototype.saveTiddler = function(tiddler,callback) {
|
||||
FileSystemAdaptor.prototype.saveTiddler = function(tiddler,callback,options) {
|
||||
var self = this;
|
||||
var syncerInfo = options.tiddlerInfo || {};
|
||||
this.getTiddlerFileInfo(tiddler,function(err,fileInfo) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
$tw.utils.saveTiddlerToFile(tiddler,fileInfo,function(err) {
|
||||
$tw.utils.saveTiddlerToFile(tiddler,fileInfo,function(err,fileInfo) {
|
||||
if(err) {
|
||||
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "open") {
|
||||
var bootInfo = self.boot.files[tiddler.fields.title];
|
||||
bootInfo.writeError = true;
|
||||
self.boot.files[tiddler.fields.title] = bootInfo;
|
||||
$tw.syncer.displayError("Sync for tiddler [["+tiddler.fields.title+"]] will be retried with encoded filepath", encodeURIComponent(bootInfo.filepath));
|
||||
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));
|
||||
return callback(err);
|
||||
} else {
|
||||
return callback(err);
|
||||
}
|
||||
}
|
||||
// Store new boot info only after successful writes
|
||||
self.boot.files[tiddler.fields.title] = fileInfo;
|
||||
// Cleanup duplicates if the file moved or changed extensions
|
||||
var options = {
|
||||
adaptorInfo: ($tw.syncer.tiddlerInfo[tiddler.fields.title] || {adaptorInfo: {} }).adaptorInfo,
|
||||
bootInfo: self.boot.files[tiddler.fields.title] || {},
|
||||
adaptorInfo: syncerInfo.adaptorInfo || {},
|
||||
bootInfo: fileInfo || {},
|
||||
title: tiddler.fields.title
|
||||
};
|
||||
$tw.utils.cleanupTiddlerFiles(options, function(err){
|
||||
$tw.utils.cleanupTiddlerFiles(options,function(err,fileInfo) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null, self.boot.files[tiddler.fields.title]);
|
||||
return callback(null,fileInfo);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -127,20 +129,22 @@ FileSystemAdaptor.prototype.deleteTiddler = function(title,callback,options) {
|
||||
fileInfo = this.boot.files[title];
|
||||
// Only delete the tiddler if we have writable information for the file
|
||||
if(fileInfo) {
|
||||
$tw.utils.deleteTiddlerFile(fileInfo, function(err){
|
||||
$tw.utils.deleteTiddlerFile(fileInfo,function(err,fileInfo) {
|
||||
if(err) {
|
||||
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
|
||||
// Error deleting the file on disk, should fail gracefully
|
||||
$tw.syncer.displayError("Server desynchronized. Error deleting file for deleted tiddler: "+title, err);
|
||||
return callback(null);
|
||||
$tw.syncer.displayError("Server desynchronized. Error deleting file for deleted tiddler \"" + title + "\"",err);
|
||||
return callback(null,fileInfo);
|
||||
} else {
|
||||
return callback(err);
|
||||
}
|
||||
}
|
||||
return callback(null);
|
||||
// Remove the tiddler from self.boot.files & return null adaptorInfo
|
||||
delete self.boot.files[title];
|
||||
return callback(null,null);
|
||||
});
|
||||
} else {
|
||||
callback(null);
|
||||
callback(null,null);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -106,7 +106,7 @@ SaveTrailSyncAdaptor.prototype.saveTiddler = function(tiddler,callback) {
|
||||
saveTiddlerFile(tiddler,{reason: "modified"});
|
||||
}
|
||||
}
|
||||
callback(null);
|
||||
callback(null,null);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -120,7 +120,7 @@ SaveTrailSyncAdaptor.prototype.loadTiddler = function(title,callback) {
|
||||
Delete a tiddler and invoke the callback with (err)
|
||||
*/
|
||||
SaveTrailSyncAdaptor.prototype.deleteTiddler = function(title,callback,options) {
|
||||
callback(null);
|
||||
callback(null,null);
|
||||
};
|
||||
|
||||
function saveTiddlerFile(tiddler,options) {
|
||||
@ -139,8 +139,8 @@ function saveTiddlerFile(tiddler,options) {
|
||||
link.setAttribute("target","_blank");
|
||||
link.setAttribute("rel","noopener noreferrer");
|
||||
if(Blob !== undefined) {
|
||||
var blob = new Blob([text], {type: "text/plain"});
|
||||
link.setAttribute("href", URL.createObjectURL(blob));
|
||||
var blob = new Blob([text],{type: "text/plain"});
|
||||
link.setAttribute("href",URL.createObjectURL(blob));
|
||||
} else {
|
||||
link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
|
||||
}
|
||||
|
@ -182,10 +182,10 @@ TiddlyWebAdaptor.prototype.getSkinnyTiddlers = function(callback) {
|
||||
/*
|
||||
Save a tiddler and invoke the callback with (err,adaptorInfo,revision)
|
||||
*/
|
||||
TiddlyWebAdaptor.prototype.saveTiddler = function(tiddler,callback) {
|
||||
TiddlyWebAdaptor.prototype.saveTiddler = function(tiddler,callback,options) {
|
||||
var self = this;
|
||||
if(this.isReadOnly) {
|
||||
return callback(null);
|
||||
return callback(null,options.tiddlerInfo.adaptorInfo);
|
||||
}
|
||||
$tw.utils.httpRequest({
|
||||
url: this.host + "recipes/" + encodeURIComponent(this.recipe) + "/tiddlers/" + encodeURIComponent(tiddler.fields.title),
|
||||
@ -207,7 +207,7 @@ TiddlyWebAdaptor.prototype.saveTiddler = function(tiddler,callback) {
|
||||
// Invoke the callback
|
||||
callback(null,{
|
||||
bag: etagInfo.bag
|
||||
}, etagInfo.revision);
|
||||
},etagInfo.revision);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -238,12 +238,12 @@ tiddlerInfo: the syncer's tiddlerInfo for this tiddler
|
||||
TiddlyWebAdaptor.prototype.deleteTiddler = function(title,callback,options) {
|
||||
var self = this;
|
||||
if(this.isReadOnly) {
|
||||
return callback(null);
|
||||
return callback(null,options.tiddlerInfo.adaptorInfo);
|
||||
}
|
||||
// If we don't have a bag it means that the tiddler hasn't been seen by the server, so we don't need to delete it
|
||||
var bag = options.tiddlerInfo.adaptorInfo && options.tiddlerInfo.adaptorInfo.bag;
|
||||
if(!bag) {
|
||||
return callback(null);
|
||||
return callback(null,options.tiddlerInfo.adaptorInfo);
|
||||
}
|
||||
// Issue HTTP request to delete the tiddler
|
||||
$tw.utils.httpRequest({
|
||||
@ -253,8 +253,8 @@ TiddlyWebAdaptor.prototype.deleteTiddler = function(title,callback,options) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
// Invoke the callback & return null adaptorInfo
|
||||
callback(null,null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user