-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Validate and install extensions (final) #3158
Conversation
existence of package.json
missing name and version metadata
…e basic unit tests
… keyboard handling in various states.
…ate, but if you can access the class show() should be public). Also, remove the installer param to _showDialog() since it's never used.
installed (installing into disabled in those cases)
legally, and the test that follows the deleted one catches validation issues in general)
the installation and mocks the extension loading to verify that the extension *would* load. disabled the test because it can only run once and will fail on the second run because there's no way to delete the target directory
(from GitHub for example)
.done(function (localPath) { | ||
state = STATE_INSTALLING; | ||
|
||
// TOOD: need to clean up ZIP from temp location |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this comment is stale now since we call unlink()
after the installation succeeds or fails below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, sorry. Removed.
@dangoor @peterflynn -- re-review (for non-UI parts) complete. I'm not going to merge right now, but will be online later tonight--Peter, if you push some fixes up before I get back online, that's cool, otherwise I'll likely go ahead and merge then; there aren't really any major showstoppers that I see, though there are a few things we should definitely address before DoD. @dangoor -- don't remember where I mentioned this before, but the main changes for the UI stuff (outside of InstallExtensionDialog) were:
|
@njx @dangoor @peterflynn Thank you guys for your hard work on this exciting pull into Brackets. Very cool! |
Validate and install extensions (final)
Went ahead and merged this. @dangoor -- if you end up having any comments on the UI stuff, feel free to add the comments to this pull request and I can look at them here later. |
.fail(function (err) { | ||
// Ignore expected case: the Promise is failed when we programmatically cancel | ||
// In all other cases, record the error and transition to error display UI | ||
if (!(err === "CANCELED" && self._state === STATE_INSTALL_CANCELLED)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an almost embarrassing nit to bring up... there are two different spellings of CANCELED on the same line. Both are legit but canceled (one L) is the more common American way. Someone could come along later and misspell STATE_INSTALL_CANCELLED as a result, but I should hope the error would be obvious and we have JS autocompletion to help anyhow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Funny, I always preferred "cancelled", but it does look like American English is standardizing on one-l, and we already have "CANCELED" elsewhere in the API (e.g. dialogs). I've fixed this locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually Peter is fixing it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've fixed this in the process of doing all the async-cancellation code.
I've finished reviewing the UI code. |
*/ | ||
function _cmdDownloadFile(downloadId, url, localPath, callback) { | ||
if (pendingDownloads[downloadId]) { | ||
callback(Errors.DOWNLOAD_ID_IN_USE, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had commented in email separately, but I thought I should put it here with the other comments as well... it appears that the convention in Node is to pass Error objects, so this (and the callback below) should really be something like
callback(new Error(Errors.DOWNLOAD_ID_IN_USE), null);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dangoor it seems like this is more analogous to the validation failures than it is to throwing an exception in synchronous code... so perhaps I should pass a success object containing an error(s) property instead? Is the first arg of the callback basically used only in cases where the code has essentially 'crashed' or hit an internal error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It also looks like our node_core code fail to JSONify Error objects properly... we'll need to fix that too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And actually of course, the standard Error.message doesn't support passing back structured data like the arrays we use for formatted errors in this file. So it seems like we have three options:
- Use the success argument with an 'error(s)' property for most problems -- anything other than unexpected, thrown exceptions. (Seems a little gross and not really how most Node treats anticipated error cases).
- Use a custom Error subclass that accepts a (non-string) data parameter, and add special logic to ConnectionManager to serialize back that parameter. (Doesn't seem that common in Node either, but still a bit cleaner than above).
- Pass something other than an Error as the first arg (some references say this is ok). (But definitely not the standard Node way).
Right now our code seems evenly split between the 1st & 3rd approaches, which is not that ideal...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where I started with this was that for validation I assumed that unless the validation routine was actually broken, the whole point was to return whether or not the extension was valid. I carried that over into installation because installation validates first.
I do think you're right that the Node convention is generally to pass (err, null)
for anything that goes wrong.
I did see one page about errors that talked about doing this:
var err = new Error("message");
err.data = {more: "stuff"};
It would certainly be more pleasant to have a constructor that can take additional data. And I do think that ConnectionManager should know what to do if the callback is given an error, since that's so common. (As some point, we should have a domain (in Node terms) to capture the errors and carry them up to the UI.)
I don't know how much work there would be in ConnectionManager, but I do think it's a good idea to stick to the node convention where possible.
Do you think validation should return (err, null) if the extension is invalid and (null, metadata) if it's valid?
if (!options || !options.disabledDirectory) { | ||
callback(new Error(Errors.NO_DISABLED_DIRECTORY), null); | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dangoor I'm wondering if we should just make disabledDirectory required... It seems like if one of the standard codepaths will always throw an error without it, it'd be nicer just to make it a required parameter and dispense with the two copies of this code that guards against it being missing.
It seems like apiVersion shouldn't be optional either... unless we're trying to generalize this code to run in some app other than Brackets, it seems safe to assume that install() can always get an API version for context. (Not true of validate() when it runs on the server, of course, but install() seems ok to assume it's running against an actual app).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'm fine with making those required (and will do so)
This supersedes #3137, and should contain just the changes for the installer pull request separate from the node modules in #3156.