From the point of view of a translator author / maintainer, this
sounds like a reasonable workflow. Alexander? Would you be up for
trying to recast the patch to work like this? And would this still
address the use case that's motivating the patch?
Avram
I agree that the proposed workflow is better for the general case than
my own, and I could definitely implement the changes.
I think these changes should cover my use case, with the exception of
filename conflicts. In my case I'm expecting to move a lot of PDF
attachment files to the same directory, and naming conflicts will
potentially be an issue. The automatic name mangling that I
implemented in the current patch is definitely hacky, and should be
replaced. Ideally I think the saveFile() call should have an optional
parameter that can be used to specify a new filename for the
attachment, and an error should be thrown if a file already exists at
the specified path / filename. This way it would be up to individual
translator authors to determine how they want to handle any possible
conflicts. In the case of snapshots the supporting files likely can't
change names, but at least an error could be thrown if any of the
supporting files would cause a name conflict. This would allow the
translator author to retry the save with a new directory (but not new
filenames). If anyone has any better ideas to deal with naming issues,
I'd be more than happy to hear them.
If saveItem() throws an error for another reason (e.g., another Mozilla
file error), the code above will result in an infinite loop. (If it
managed to save before the error, you could even fill up the filesystem
with duplicate files.) You should either add a fail-safe counter or,
better yet, throw and test for a specific error (see error.js and
examples in sync.js).
OK, but this has implications for the patch, which is why I bring it up.
What are you planning to test against to know whether you need to
increment the counter or just re-throw the error? You're throwing an
Error object in a few places in saveItem (which isn't necessary, by the
way�throwing a string is fine if you're not using the other Error
properties), so all you can do is look for that particular
human-readable error string ("A file already exists at the specified
file path"), which isn't particularly good practice. Using an object
with a specific property is probably overkill (and I guess translators
won't have access to Zotero.Error anyway), but you should at least
include a specific code in the thrown string (e.g., "ERROR_FILE_EXISTS")
that won't change and that translators can look for.
But my point is that "e instanceof Error" will match all cases of Error
being thrown�not just the file-exists error�as well as potentially other
JS errors, so saveItem() needs to include something more specific to
test against. (For example, in your current code, an empty path, which
could easily happen by accident, would result in an endless loop, as you
throw an Error there too. Same if some other Error was added to the
function at a later point.) The easiest approach, I'm suggesting, is
just to add "ERROR_FILE_EXISTS" to the error string, and translators can
look for that.
(As a side note, despite my earlier claim, Simon points out that
throwing an Error object (vs. a string) does have the advantage of
automatically including a line number and stack trace.)