Fixes #724, PDF indexing binaries not downloading

And adds Zotero.File.download(uri, path)
This commit is contained in:
Dan Stillman 2015-05-23 18:03:25 -04:00
parent 6b87c641d9
commit ebe41ac51a
4 changed files with 296 additions and 266 deletions

View file

@ -161,15 +161,15 @@ Zotero_Preferences.Search = {
* Check available versions of PDF tools from server and prompt for installation
* if a newer version is available
*/
checkPDFToolsDownloadVersion: function () {
checkPDFToolsDownloadVersion: Zotero.Promise.coroutine(function* () {
var url = Zotero.Fulltext.pdfToolsDownloadBaseURL + 'latest.json';
// Find latest version for this platform
var self = this;
var sent = Zotero.HTTP.doGet(url, function (xmlhttp) {
try {
if (xmlhttp.status != 200) {
throw new Error("Unexpected response code " + xmlhttp.status);
var xmlhttp = yield Zotero.HTTP.request("GET", url, { successCodes: [200, 404] });
if (xmlhttp.status == 404) {
throw 404;
}
var platform = Zotero.platform.replace(/\s/g, '-');
@ -216,9 +216,10 @@ Zotero_Preferences.Search = {
var button = document.getElementById('pdftools-update-button');
button.setAttribute('label', Zotero.getString('zotero.preferences.update.upToDate'));
button.setAttribute('disabled', true);
return;
}
// New version available -- display update prompt
else {
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
createInstance(Components.interfaces.nsIPromptService);
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
@ -252,57 +253,34 @@ Zotero_Preferences.Search = {
Zotero.getString('general.install'),
null, null, null, {});
if (index == 0) {
if (index != 0) {
return;
}
document.getElementById('pdftools-update-button').disabled = true;
var str = Zotero.getString('zotero.preferences.search.pdf.downloading');
document.getElementById('pdftools-update-button').setAttribute('label', str);
if (converterVersionAvailable && infoVersionAvailable) {
Zotero.Fulltext.downloadPDFTool('converter', latestVersion, function (success) {
if (!success) {
self.onPDFToolsDownloadError("Error downloading pdftotext");
return;
}
Zotero.Fulltext.downloadPDFTool('info', latestVersion, function (success) {
if (!success) {
self.onPDFToolsDownloadError("Error downloading pdfinfo");
return;
}
self.updatePDFToolsStatus();
});
if (converterVersionAvailable) {
yield Zotero.Fulltext.downloadPDFTool('converter', latestVersion)
.catch(function (e) {
Zotero.logError(e);
throw new Error("Error downloading pdftotext");
});
}
else if (converterVersionAvailable) {
Zotero.Fulltext.downloadPDFTool('converter', latestVersion, function (success) {
if (!success) {
self.onPDFToolsDownloadError("Error downloading pdftotext");
return;
}
self.updatePDFToolsStatus();
if (infoVersionAvailable) {
yield Zotero.Fulltext.downloadPDFTool('info', latestVersion)
.catch(function (e) {
Zotero.logError(e);
throw new Error("Error downloading pdfinfo");
});
}
else {
Zotero.Fulltext.downloadPDFTool('info', latestVersion, function (success) {
if (!success) {
self.onPDFToolsDownloadError("Error downloading pdfinfo");
return;
}
self.updatePDFToolsStatus();
});
}
}
}
this.updatePDFToolsStatus();
}
catch (e) {
self.onPDFToolsDownloadError(e);
this.onPDFToolsDownloadError(e);
}
});
// Browser is offline
if (!sent) {
this.onPDFToolsDownloadError();
}
},
}),
onPDFToolsDownloadError: function (e) {
@ -311,17 +289,11 @@ Zotero_Preferences.Search = {
Zotero.Fulltext.pdfToolsName) + ' '
+ Zotero.getString('zotero.preferences.search.pdf.viewManualInstructions');
}
else if (e) {
else {
Components.utils.reportError(e);
var str = Zotero.getString('zotero.preferences.search.pdf.toolsDownloadError', Zotero.Fulltext.pdfToolsName)
+ ' ' + Zotero.getString('zotero.preferences.search.pdf.tryAgainOrViewManualInstructions');
}
else {
var info = Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo);
var browser = info.name; // Returns "Firefox" for Firefox
var str = Zotero.getString('general.browserIsOffline', browser);
}
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.createInstance(Components.interfaces.nsIPromptService);

View file

@ -355,7 +355,7 @@ Zotero.File = new function(){
));
}
// Create a stream for async stream copying
// Convert text data to stream
if(!(data instanceof Components.interfaces.nsIInputStream)) {
var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
@ -363,9 +363,9 @@ Zotero.File = new function(){
data = converter.convertToInputStream(data);
}
var deferred = Zotero.Promise.defer(),
ostream = FileUtils.openSafeFileOutputStream(path);
NetUtil.asyncCopy(data, ostream, function(inputStream, status) {
var deferred = Zotero.Promise.defer();
var os = FileUtils.openSafeFileOutputStream(new FileUtils.File(path));
NetUtil.asyncCopy(data, os, function(inputStream, status) {
if (!Components.isSuccessCode(status)) {
deferred.reject(new Components.Exception("File write operation failed", status));
return;
@ -376,6 +376,23 @@ Zotero.File = new function(){
};
this.download = Zotero.Promise.coroutine(function* (uri, path) {
var msg = "Saving " + (uri.spec ? uri.spec : uri) + " to " + (path.path ? path.path : path);
var deferred = Zotero.Promise.defer();
NetUtil.asyncFetch(uri, function (is, status, request) {
if (!Components.isSuccessCode(status)) {
Zotero.logError(status);
deferred.reject(new Error("Download failed with status " + status));
return;
}
deferred.resolve(is);
});
var is = yield deferred.promise;
yield Zotero.File.putContentsAsync(path, is);
});
/**
* Delete a file if it exists, asynchronously
*

View file

@ -30,7 +30,7 @@ Zotero.Fulltext = new function(){
this.pdfInfoIsRegistered = pdfInfoIsRegistered;
this.isCachedMIMEType = isCachedMIMEType;
this.__defineGetter__("pdfToolsDownloadBaseURL", function() { return 'https://www.zotero.org/download/xpdf/'; });
this.pdfToolsDownloadBaseURL = 'https://www.zotero.org/download/xpdf/';
this.__defineGetter__("pdfToolsName", function() { return 'Xpdf'; });
this.__defineGetter__("pdfToolsURL", function() { return 'http://www.foolabs.com/xpdf/'; });
this.__defineGetter__("pdfConverterName", function() { return 'pdftotext'; });
@ -132,8 +132,7 @@ Zotero.Fulltext = new function(){
/*
* Download and install latest PDF tool
*/
this.downloadPDFTool = function (tool, version, callback) {
try {
this.downloadPDFTool = Zotero.Promise.coroutine(function* (tool, version) {
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
@ -146,42 +145,23 @@ Zotero.Fulltext = new function(){
var spec = this.pdfToolsDownloadBaseURL + version + "/" + fileName;
var uri = ioService.newURI(spec, null, null);
var tmpFile = OS.Path.join(Zotero.getTempDirectory().path, fileName);
var file = Zotero.getTempDirectory();
file.append(fileName);
yield Zotero.File.download(uri, tmpFile);
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
var fileInfo = yield OS.File.stat(tmpFile);
Zotero.debug("Saving " + uri.spec + " to " + file.path);
NetUtil.asyncFetch(uri, function (is, status) {
if (!Components.isSuccessCode(status)) {
Zotero.debug(status, 1);
Components.utils.reportError(status);
if (callback) {
callback(false);
}
return;
}
Zotero.File.putContentsAsync(file, is)
.then(function () {
// Delete if too small, since a 404 might not be detected above
if (file.fileSize < 50000) {
var msg = file.path + " is too small -- deleting";
Zotero.debug(msg, 1);
Components.utils.reportError(msg);
if (fileInfo.size < 50000) {
let msg = tmpFile + " is too small -- deleting";
Zotero.logError(msg);
try {
file.remove(false);
yield OS.File.remove(tmpFile);
}
catch (e) {
Zotero.debug(e, 1);
Components.utils.reportError(e);
Zotero.logError(e);
}
if (callback) {
callback(false);
}
return;
throw new Error(msg);
}
var scriptExt = _getScriptExtension();
@ -189,41 +169,50 @@ Zotero.Fulltext = new function(){
// TEMP: disabled
if (false && tool == 'converter') {
if (Zotero.isWin) {
var content = Zotero.File.getContentsFromURL('resource://zotero/hide.' + scriptExt);
var scriptFile = Zotero.getTempDirectory();
scriptFile.append('pdftotext.' + scriptExt);
Zotero.File.putContents(scriptFile, content);
let content = yield Zotero.File.getContentsFromURLAsync(
'resource://zotero/hide.' + scriptExt
);
var tmpScriptFile = OS.Path.join(
Zotero.getTempDirectory().path,
'pdftotext.' + scriptExt
);
yield Zotero.File.putContentsAsync(tmpScriptFile, content);
}
}
// Write out output redirection script for pdfinfo
// TEMP: disabled on Windows
else if (!Zotero.isWin && tool == 'info') {
var content = Zotero.File.getContentsFromURL('resource://zotero/redirect.' + scriptExt);
var scriptFile = Zotero.getTempDirectory();
scriptFile.append('pdfinfo.' + scriptExt);
Zotero.File.putContents(scriptFile, content);
let content = yield Zotero.File.getContentsFromURLAsync(
'resource://zotero/redirect.' + scriptExt
);
var tmpScriptFile = OS.Path.join(
Zotero.getTempDirectory().path,
'pdfinfo.' + scriptExt
);
yield Zotero.File.putContentsAsync(tmpScriptFile, content);
}
// Set permissions to 755
if (Zotero.isMac) {
file.permissions = 33261;
if (scriptFile) {
scriptFile.permissions = 33261;
}
}
else if (Zotero.isLinux) {
file.permissions = 493;
if (scriptFile) {
scriptFile.permissions = 493;
if (Zotero.isMac || Zotero.isLinux) {
yield OS.File.setPermissions(tmpFile, {
unixMode: 0o755
});
if (tmpScriptFile) {
yield OS.File.setPermissions(tmpScriptFile, {
unixMode: 0o755
});
}
}
var destDir = Zotero.getZoteroDirectory()
// Move redirect script and executable into data dir
if (scriptFile) {
scriptFile.moveTo(destDir, null);
if (tmpScriptFile) {
yield OS.File.move(
tmpScriptFile,
OS.Path.join(destDir.path, OS.Path.basename(tmpScriptFile))
);
}
file.moveTo(destDir, null);
yield OS.File.move(tmpFile, OS.Path.join(destDir.path, fileName));
// Write the version number to a file
var versionFile = destDir.clone();
@ -232,29 +221,10 @@ Zotero.Fulltext = new function(){
if (Zotero.isWin) {
version = '3.02a';
}
Zotero.File.putContents(versionFile, version + '');
yield Zotero.File.putContentsAsync(versionFile, version + '');
Zotero.Fulltext.registerPDFTool(tool);
if (callback) {
callback(true);
}
})
.catch(function (e) {
Zotero.debug(e, 1);
Components.utils.reportError(e);
callback(false);
yield Zotero.Fulltext.registerPDFTool(tool);
});
});
}
catch (e) {
Zotero.debug(e, 1);
Components.utils.reportError(e);
if (callback) {
callback(false);
}
}
};
/*

View file

@ -0,0 +1,71 @@
describe("Zotero.Fulltext", function () {
describe("#downloadPDFTool()", function () {
var originalBaseURL;
before(function* () {
originalBaseURL = Zotero.Fulltext.pdfToolsDownloadBaseURL;
})
after(function () {
Zotero.Fulltext.pdfToolsDownloadBaseURL = originalBaseURL;
})
it("should install the PDF tools", function* () {
var version = "3.04";
var dataDir = Zotero.getZoteroDirectory().path;
var execFileName = 'pdfinfo-' + Zotero.platform;
var execContents = new Array(50001).join('a');
var execPath = OS.Path.join(dataDir, execFileName);
var versionFileName = execFileName + '.version';
var versionPath = OS.Path.join(dataDir, versionFileName);
var scriptExt = Zotero.isWin ? 'vbs' : 'sh';
var scriptPath = OS.Path.join(dataDir, 'pdfinfo.' + scriptExt);
var scriptContents = yield Zotero.File.getContentsFromURLAsync(
'resource://zotero/redirect.' + scriptExt
);
// Delete existing files
try {
yield OS.File.remove(execPath);
}
catch (e) {}
try {
yield OS.File.remove(versionPath);
}
catch (e) {}
try {
yield OS.File.remove(scriptPath);
}
catch (e) {}
var tmpDir = Zotero.getTempDirectory();
// Create temp version directory
var tmpVersionDir = OS.Path.join(tmpDir.path, version);
yield OS.File.makeDir(tmpVersionDir);
// Create dummy executable file to download
var tmpExecPath = OS.Path.join(tmpVersionDir, execFileName);
yield Zotero.File.putContentsAsync(tmpExecPath, execContents);
// Override the download URL with a file URL for the temp directory
Zotero.Fulltext.pdfToolsDownloadBaseURL = OS.Path.toFileURI(tmpDir.path) + "/";
yield Zotero.Fulltext.downloadPDFTool('info', version);
assert.ok(Zotero.Fulltext.pdfInfoIsRegistered());
assert.equal(
(yield Zotero.File.getContentsAsync(execPath)),
execContents
);
assert.equal((yield OS.File.stat(execPath)).unixMode, 0o755);
assert.equal(
(yield Zotero.File.getContentsAsync(versionPath)),
version
);
assert.equal(
(yield Zotero.File.getContentsAsync(scriptPath)),
scriptContents
);
assert.equal((yield OS.File.stat(scriptPath)).unixMode, 0o755);
yield OS.File.removeDir(tmpVersionDir);
})
})
})