commit 88627adcdb53d0c862914b305f7ecf378b4ab29b
parent 9e356a7e639ab4834894af46db036cb1019e38c2
Author: Dan Stillman <dstillman@zotero.org>
Date: Tue, 29 Sep 2015 04:05:13 -0400
Update linked attachment base directory code
- Replace nsIFile and persistent descriptors with OS.File and string paths
- Add tests for base dir settings
Diffstat:
3 files changed, 217 insertions(+), 78 deletions(-)
diff --git a/chrome/content/zotero/preferences/preferences_advanced.js b/chrome/content/zotero/preferences/preferences_advanced.js
@@ -323,69 +323,77 @@ Zotero_Preferences.Advanced = {
Zotero_Preferences.Attachment_Base_Directory = {
- choosePath: function () {
- // Get existing base directory
- var oldBasePath = Zotero.Prefs.get('baseAttachmentPath');
- if (oldBasePath) {
- var oldBasePathFile = Components.classes["@mozilla.org/file/local;1"]
- .createInstance(Components.interfaces.nsILocalFile);
+ getPath: function () {
+ var oldPath = Zotero.Prefs.get('baseAttachmentPath');
+ if (oldPath) {
try {
- oldBasePathFile.persistentDescriptor = oldBasePath;
+ return OS.Path.normalize(oldPath);
}
catch (e) {
- Zotero.debug(e, 1);
- Components.utils.reportError(e);
- oldBasePathFile = null;
+ Zotero.logError(e);
+ return false;
}
}
+ },
+
+
+ choosePath: Zotero.Promise.coroutine(function* () {
+ var oldPath = this.getPath();
//Prompt user to choose new base path
+ if (oldPath) {
+ var oldPathFile = Zotero.File.pathToFile(oldPath);
+ }
var nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
- if (oldBasePathFile) {
- fp.displayDirectory = oldBasePathFile;
+ if (oldPathFile) {
+ fp.displayDirectory = oldPathFile;
}
fp.init(window, Zotero.getString('attachmentBasePath.selectDir'), nsIFilePicker.modeGetFolder);
fp.appendFilters(nsIFilePicker.filterAll);
if (fp.show() != nsIFilePicker.returnOK) {
return false;
}
- var newBasePathFile = fp.file;
+ var newPath = OS.Path.normalize(fp.file.path);
- if (oldBasePathFile && oldBasePathFile.equals(newBasePathFile)) {
+ if (oldPath && oldPath == newPath) {
Zotero.debug("Base directory hasn't changed");
return false;
}
+ return changePath(newPath);
+ }),
+
+
+ changePath: Zotero.Promise.coroutine(function* (basePath) {
// Find all current attachments with relative attachment paths
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=? AND path LIKE '"
+ Zotero.Attachments.BASE_PATH_PLACEHOLDER + "%'";
var params = [Zotero.Attachments.LINK_MODE_LINKED_FILE];
- var oldRelativeAttachmentIDs = Zotero.DB.columnQuery(sql, params) || [];
+ var oldRelativeAttachmentIDs = yield Zotero.DB.columnQueryAsync(sql, params);
//Find all attachments on the new base path
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=?";
var params = [Zotero.Attachments.LINK_MODE_LINKED_FILE];
- var allAttachments = Zotero.DB.columnQuery(sql,params);
+ var allAttachments = yield Zotero.DB.columnQueryAsync(sql, params);
var newAttachmentPaths = {};
var numNewAttachments = 0;
var numOldAttachments = 0;
- var attachmentFile = Components.classes["@mozilla.org/file/local;1"]
- .createInstance(Components.interfaces.nsILocalFile);
for (let i=0; i<allAttachments.length; i++) {
let attachmentID = allAttachments[i];
+ let attachmentPath;
let relPath = false
try {
- let attachment = Zotero.Items.get(attachmentID);
+ let attachment = yield Zotero.Items.getAsync(attachmentID);
// This will return FALSE for relative paths if base directory
// isn't currently set
- attachmentFile = attachment.getFile(false, true);
+ attachmentPath = attachment.getFilePath();
// Get existing relative path
- let path = attachment.attachmentPath;
- if (path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) == 0) {
- relPath = path.substr(Zotero.Attachments.BASE_PATH_PLACEHOLDER.length);
+ let storedPath = attachment.attachmentPath;
+ if (storedPath.startsWith(Zotero.Attachments.BASE_PATH_PLACEHOLDER)) {
+ relPath = storedPath.substr(Zotero.Attachments.BASE_PATH_PLACEHOLDER.length);
}
}
catch (e) {
@@ -397,10 +405,7 @@ Zotero_Preferences.Attachment_Base_Directory = {
// If a file with the same relative path exists within the new base directory,
// don't touch the attachment, since it will continue to work
if (relPath) {
- let relFile = Components.classes["@mozilla.org/file/local;1"]
- .createInstance(Components.interfaces.nsILocalFile);
- relFile.setRelativeDescriptor(newBasePathFile, relPath);
- if (relFile.exists()) {
+ if (yield OS.File.exists(OS.Path.join(basePath, relPath))) {
numNewAttachments++;
continue;
}
@@ -409,15 +414,14 @@ Zotero_Preferences.Attachment_Base_Directory = {
// Files within the new base directory need to be updated to use
// relative paths (or, if the new base directory is an ancestor or
// descendant of the old one, new relative paths)
- if (attachmentFile && Zotero.File.directoryContains(newBasePathFile, attachmentFile)) {
- newAttachmentPaths[attachmentID] = relPath
- ? attachmentFile.persistentDescriptor : null;
+ if (attachmentPath && Zotero.File.directoryContains(basePath, attachmentPath)) {
+ newAttachmentPaths[attachmentID] = relPath ? attachmentPath : null;
numNewAttachments++;
}
// Existing relative attachments not within the new base directory
// will be converted to absolute paths
- else if (relPath && oldBasePathFile) {
- newAttachmentPaths[attachmentID] = attachmentFile.persistentDescriptor;
+ else if (relPath && this.getPath()) {
+ newAttachmentPaths[attachmentID] = attachmentPath;
numOldAttachments++;
}
}
@@ -475,50 +479,41 @@ Zotero_Preferences.Attachment_Base_Directory = {
// Set new data directory
Zotero.debug("Setting new base directory");
- Zotero.Prefs.set('baseAttachmentPath', newBasePathFile.persistentDescriptor);
+ Zotero.Prefs.set('baseAttachmentPath', basePath);
Zotero.Prefs.set('saveRelativeAttachmentPath', true);
// Resave all attachments on base path (so that their paths become relative)
// and all other relative attachments (so that their paths become absolute)
- for (let id in newAttachmentPaths) {
- let attachment = Zotero.Items.get(id);
- if (newAttachmentPaths[id]) {
- attachment.attachmentPath = newAttachmentPaths[id];
- attachment.save({
- skipDateModifiedUpdate: true
- });
- }
- else {
- attachment.updateAttachmentPath();
+ yield Zotero.Utilities.Internal.forEachChunkAsync(
+ Object.keys(newAttachmentPaths),
+ 100,
+ function (chunk) {
+ return Zotero.DB.executeTransaction(function* () {
+ for (let id of chunk) {
+ let attachment = Zotero.Items.get(id);
+ if (newAttachmentPaths[id]) {
+ attachment.attachmentPath = newAttachmentPaths[id];
+ }
+ else {
+ attachment.attachmentPath = attachment.getFilePath();
+ }
+ yield attachment.save({
+ skipDateModifiedUpdate: true
+ });
+ }
+ })
}
- }
- return newBasePathFile.persistentDescriptor;
- },
-
-
- getPath: function (asFile) {
- var desc = Zotero.Prefs.get('baseAttachmentPath');
- if (desc == '') {
- return asFile ? null : '';
- }
+ );
- var file = Components.classes["@mozilla.org/file/local;1"]
- .createInstance(Components.interfaces.nsILocalFile);
- try {
- file.persistentDescriptor = desc;
- }
- catch (e) {
- return asFile ? null : '';
- }
- return asFile ? file : file.path;
- },
+ return true;
+ }),
- clearPath: function () {
+ clearPath: Zotero.Promise.coroutine(function* () {
// Find all current attachments with relative paths
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=? AND path LIKE '"
+ Zotero.Attachments.BASE_PATH_PLACEHOLDER + "%'";
var params = [Zotero.Attachments.LINK_MODE_LINKED_FILE];
- var relativeAttachmentIDs = Zotero.DB.columnQuery(sql, params) || [];
+ var relativeAttachmentIDs = yield Zotero.DB.columnQueryAsync(sql, params);
// Prompt for confirmation
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
@@ -562,26 +557,40 @@ Zotero_Preferences.Attachment_Base_Directory = {
// attachments so that their absolute paths are stored
Zotero.debug('Clearing base directory');
Zotero.Prefs.set('saveRelativeAttachmentPath', false);
- for (var i=0; i<relativeAttachmentIDs.length; i++) {
- Zotero.Items.get(relativeAttachmentIDs[i]).updateAttachmentPath();
- }
+
+ yield Zotero.Utilities.Internal.forEachChunkAsync(
+ relativeAttachmentIDs,
+ 100,
+ function (chunk) {
+ return Zotero.DB.executeTransaction(function* () {
+ for (let id of chunk) {
+ let attachment = yield Zotero.Items.getAsync(id);
+ attachment.attachmentPath = attachment.getFilePath();
+ yield attachment.save({
+ skipDateModifiedUpdate: true
+ });
+ }
+ }.bind(this));
+ }.bind(this)
+ );
+
Zotero.Prefs.set('baseAttachmentPath', '');
- },
+ }),
- updateUI: function () {
+ updateUI: Zotero.Promise.coroutine(function* () {
var filefield = document.getElementById('baseAttachmentPath');
- var file = this.getPath(true);
- filefield.file = file;
- if (file) {
- filefield.label = file.path;
+ var path = Zotero.Prefs.get('baseAttachmentPath');
+ Components.utils.import("resource://gre/modules/osfile.jsm");
+ if (yield OS.File.exists(path)) {
+ filefield.file = Zotero.File.pathToFile(path);
+ filefield.label = path;
}
else {
filefield.label = '';
}
-
- document.getElementById('resetBasePath').disabled = !Zotero.Prefs.get('baseAttachmentPath');
- }
+ document.getElementById('resetBasePath').disabled = !path;
+ })
};
diff --git a/chrome/content/zotero/preferences/preferences_advanced.xul b/chrome/content/zotero/preferences/preferences_advanced.xul
@@ -154,7 +154,8 @@
readonly="true"
flex="1"
tabindex="-1"/>
- <button label="&zotero.preferences.attachmentBaseDir.selectBasePath;"
+ <button id="baseAttachmentPathButton"
+ label="&zotero.preferences.attachmentBaseDir.selectBasePath;"
oncommand="Zotero_Preferences.Attachment_Base_Directory.choosePath()"/>
</hbox>
diff --git a/test/tests/preferences_advancedTest.js b/test/tests/preferences_advancedTest.js
@@ -0,0 +1,129 @@
+describe("Advanced Preferences", function () {
+ describe("Files & Folders", function () {
+ describe("Linked Attachment Base Directory", function () {
+ var setBaseDirectory = Zotero.Promise.coroutine(function* (basePath) {
+ var win = yield loadWindow("chrome://zotero/content/preferences/preferences.xul", {
+ pane: 'zotero-prefpane-advanced',
+ tabIndex: 1
+ });
+
+ // Wait for tab to load
+ var doc = win.document;
+ var prefwindow = doc.documentElement;
+ var defer = Zotero.Promise.defer();
+ var pane = doc.getElementById('zotero-prefpane-advanced');
+ if (!pane.loaded) {
+ pane.addEventListener('paneload', function () {
+ defer.resolve();
+ })
+ yield defer.promise;
+ }
+
+ var promise = waitForDialog();
+ yield win.Zotero_Preferences.Attachment_Base_Directory.changePath(basePath);
+ yield promise;
+
+ win.close();
+ });
+
+ var clearBaseDirectory = Zotero.Promise.coroutine(function* (basePath) {
+ var win = yield loadWindow("chrome://zotero/content/preferences/preferences.xul", {
+ pane: 'zotero-prefpane-advanced',
+ tabIndex: 1
+ });
+
+ // Wait for tab to load
+ var doc = win.document;
+ var prefwindow = doc.documentElement;
+ var defer = Zotero.Promise.defer();
+ var pane = doc.getElementById('zotero-prefpane-advanced');
+ if (!pane.loaded) {
+ pane.addEventListener('paneload', function () {
+ defer.resolve();
+ })
+ yield defer.promise;
+ }
+
+ var promise = waitForDialog();
+ yield win.Zotero_Preferences.Attachment_Base_Directory.clearPath();
+ yield promise;
+
+ win.close();
+ });
+
+ beforeEach(function () {
+ Zotero.Prefs.clear('baseAttachmentPath');
+ Zotero.Prefs.clear('saveRelativeAttachmentPath');
+ });
+
+ it("should set new base directory", function* () {
+ var basePath = getTestDataDirectory().path;
+ yield setBaseDirectory(basePath);
+ assert.equal(Zotero.Prefs.get('baseAttachmentPath'), basePath);
+ assert.isTrue(Zotero.Prefs.get('saveRelativeAttachmentPath'));
+ })
+
+ it("should clear base directory", function* () {
+ var basePath = getTestDataDirectory().path;
+ yield setBaseDirectory(basePath);
+ yield clearBaseDirectory();
+
+ assert.equal(Zotero.Prefs.get('baseAttachmentPath'), '');
+ assert.isFalse(Zotero.Prefs.get('saveRelativeAttachmentPath'));
+ })
+
+ it("should change absolute path of linked attachment under new base dir to prefixed path", function* () {
+ var file = getTestDataDirectory();
+ file.append('test.png');
+ var attachment = yield Zotero.Attachments.linkFromFile({ file });
+ assert.equal(attachment.attachmentPath, file.path);
+
+ var basePath = getTestDataDirectory().path;
+ yield setBaseDirectory(basePath);
+
+ assert.equal(
+ attachment.attachmentPath,
+ Zotero.Attachments.BASE_PATH_PLACEHOLDER + 'test.png'
+ );
+ })
+
+ it("should change prefixed path to absolute when changing base directory", function* () {
+ var basePath = getTestDataDirectory().path;
+ yield setBaseDirectory(basePath);
+
+ var file = getTestDataDirectory();
+ file.append('test.png');
+ var attachment = yield Zotero.Attachments.linkFromFile({ file });
+ assert.equal(
+ attachment.attachmentPath,
+ Zotero.Attachments.BASE_PATH_PLACEHOLDER + 'test.png'
+ );
+
+ var basePath = Zotero.getTempDirectory().path;
+ yield setBaseDirectory(basePath);
+
+ assert.equal(attachment.attachmentPath, file.path);
+ })
+
+ it("should change prefixed path to absolute when clearing base directory", function* () {
+ var basePath = getTestDataDirectory().path;
+ yield setBaseDirectory(basePath);
+
+ var file = getTestDataDirectory();
+ file.append('test.png');
+ var attachment = yield Zotero.Attachments.linkFromFile({ file });
+ assert.equal(
+ attachment.attachmentPath,
+ Zotero.Attachments.BASE_PATH_PLACEHOLDER + 'test.png'
+ );
+
+ yield clearBaseDirectory();
+
+ assert.equal(Zotero.Prefs.get('baseAttachmentPath'), '');
+ assert.isFalse(Zotero.Prefs.get('saveRelativeAttachmentPath'));
+
+ assert.equal(attachment.attachmentPath, file.path);
+ })
+ })
+ })
+})