-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Conversation
Awesome! @mbhavi Can you add some screenshots of the new flow? |
Is there a preference to disable auto updates? |
@abose , there isn't a preference to disable auto updates. |
Sometimes, users disable auto-updates to prevent breaking changes to their setup[extension compatibilities Et.Al.]. It would be good if it is configurable by a preference without having to remove the extension. |
@abose, I have attached the screenshots and the step-by-step workflow description. |
var DIRTY_FILESAVE_CANCELLED = "dirtyFileSaveCancelled"; | ||
|
||
/** | ||
Event triggered when error is returned when tried to check if Auto Update is progress |
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.
nit: trying
instead of tried.
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.
Addressed this in 537430b
* Checks and handles if auto update is currently in progress | ||
*/ | ||
function checkIfAutoUpdateInProgress() { | ||
brackets.app.isAutoUpdateInProgress(function (err, isAutoUpdateInProgress) { |
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.
Add if (brackets.app.isAutoUpdateInProgress) {
to check if this function is registered or not.
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.
isAutoUpdateInProgress() function has been added to the core. It is not a registered function. Hence, we need not have this check.
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.
@mbhavi It is a registered in appshell_extensions.js
. Consider this scenario where a user who is running the older shell but with newer brackets
code, will never find this function, so it is a good idea to bailout. Please add a check here.
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 strongly believe suppressing the error would turn out to be harmful in this case, not showing the error to the user would be misleading to him/her believing that the feature can work with just the brackets changes.
Moreover, I don't see that with any of the other functions' invocations. I believe doing that will be unnecessary bloating of the code, as this is most likely to happen only in the dev machines, which I think should be okay.
*/ | ||
function checkIfAutoUpdateInProgress() { | ||
brackets.app.isAutoUpdateInProgress(function (err, isAutoUpdateInProgress) { | ||
if (err === 0 && isAutoUpdateInProgress) { |
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.
No need for an explicit check, general rule we follow in Brackets
is to check for error condition first. So your statements should be
if (err) {
} else {
}
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.
Addressed this in 537430b
function checkIfAutoUpdateInProgress() { | ||
brackets.app.isAutoUpdateInProgress(function (err, isAutoUpdateInProgress) { | ||
if (err === 0 && isAutoUpdateInProgress) { | ||
CommandManager.trigger(exports.DIRTY_FILESAVE_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.
Use execute
over trigger
.
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.
Help me understand. The name of the method is checkIfAutoUpdateInProgress
but you are executing exports.DIRTY_FILESAVE_CANCELLED
? Shouldn't this be something like whoever is calling this method, should be returned a promise and the client can then act upon the promise state.
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 have now placed all the events related to Auto Update, needed in core, in UpdateNotification in order to ensure consistency.
Also, I now chose a better name for checkIfAutoUpdateProgress(). It is actually a handler function. It iinternally calls a function isAutoUpdateInProgress(), which returns a bool, and the wrapper function handles this bool. So, I have renamed the wrapper function to handleIfAutoUpdateInProgress().
Please refer to 537430b
@@ -996,6 +1020,7 @@ define(function (require, exports, module) { | |||
if (selectedPath) { | |||
_doSaveAfterSaveDialog(selectedPath); | |||
} else { | |||
checkIfAutoUpdateInProgress(); |
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.
Could you explain (workflow) why this call is required here?
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 needed for the workflow where user clicked Restart button for the update to happen, but had some dirty files, because of which the app could not be quit, and instead, he got the Unsaved Files dialog, This dialog has 3 buttons : Save/Don't Save/Cancel. If Don't Save is pressed, we quit the app and run the update. If Save is pressed and user saves the file successfully, then also we quit the app and update. But when the user chooses to either press Cancel button in the above dialog, or presses Save followed by Cancel in the Save As dialog, we show him a message saying that the update will now be reflected on relaunch, which inherently means that the update will now be carried out the next time the app quits.
So, for this, we need to know whether or not the save file was cancelled by either of the two scenarios mentioned here, so that we can prompt him with the required message.
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.
Thanks for explanation @mbhavi
@@ -1217,6 +1242,7 @@ define(function (require, exports, module) { | |||
) | |||
.done(function (id) { | |||
if (id === Dialogs.DIALOG_BTN_CANCEL) { | |||
checkIfAutoUpdateInProgress(); |
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 most of the auto update code is written as an extension. In that case, you should only send notifications about the relevant events here and let the extension react to those notifications.
Eg: You should send a notification which says save cancelled/file save failed e.t.c.
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 am indeed sending the notification of a Cancel click on dirty file save operation. Please refer to my comments above.
_file = FileSystem.getFileForPath(this.path); | ||
|
||
_file.exists(function (err, exists) { | ||
if (exists) { |
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.
Check for err
.
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.
Addressed in 537430b
*/ | ||
function _write(filePath, json) { | ||
var result = $.Deferred(), | ||
_file = FileSystem.getFileForPath(filePath); |
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.
check for validity of _file
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.
_write is an internal function, which I have wrapped inside the function writePromise(), which in turn, is wrapped inside the write() function, which checks for the validity of the file. Hence, checking here is redundant.
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 think there is not harm in checking for validity of _file
given the fact that you are going to stringify
the JSON irrespective of whether _file
is valid or not.
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.
@nethip , the requirement here is to do a force write. If the file exists, the content is overwritten. If it doesn't exist, the file is created and written. I am passing the boolean to be "true" in writeText, which ensures this.
Hence, the validity is not needed here.
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.
@mbhavi Let us not have discussion of having a null check or not. It is a simple null
check. If you still feel that is not required, post merging this PR, one of us will add 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.
}); | ||
|
||
$restart.keyup(function (e) { | ||
if (e.which === 32) { //32 is the keycode for space key |
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.
use a named variable for better readability.
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.
Addressed in 537430b
updateDir = appSupportDirectory + '/updateTemp', | ||
updateJsonPath = updateDir + '/' + 'updateHelper.json'; | ||
|
||
var updateJsonHandler = new StateHandler.StateHandler(updateJsonPath); |
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.
StateHandler.StateHandler?
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.
Addressed in 537430b
|
||
/** | ||
* Checks if it is the first iteration of download | ||
* @returns {boolean} - true if first iteration, false if is a retrial of download |
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.
nit: if it is a
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.
Addressed in 537430b
* to be called in case of | ||
* successful setting of update state | ||
*/ | ||
function setUpdateStateInJSON(key, value, callback) { |
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.
Use a promise instead of a callback.
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 indeed a promise based function. The same promise handling code snippet was getting used at multiple places, and so, in order to avoid the repetition of code, I have templatized the code snippet.
*/ | ||
function handleSafeToDownload() { | ||
|
||
var downloadCB = function() { |
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.
Use promises rather than callbacks.
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.
Please refer to my comment above.
functionMap["brackets.registerBracketsFunctions"] = registerBracketsFunctions; | ||
|
||
UpdateNotification.on(UpdateNotification.GET_AUTOUPDATE_INSTALLER, handleGetNow); | ||
CommandManager.on(DocumentCommandHandlers.DIRTY_FILESAVE_CANCELLED, dirtyFileSaveCancelled); |
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.
Refer to the comment that I put above in DocumentCommandHandler
about generic command handlers.
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.
Please refer to my comments in DocumentCommandHandlers and UpdateNotification, where I have explained the use cases and requirements.
}); | ||
updateDomain.on('data', receiveMessageFromNode); | ||
|
||
AppInit.appReady(function () { |
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.
Check for platform and only then initialize AppInit.appReady as auto update is targeted for only Win and Mac.
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.
Addressed in 537430b
UpdateInfoBar = require("UpdateInfoBar"); | ||
|
||
|
||
var _modulePath = FileUtils.getNativeModuleDirectoryPath(module), |
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.
Execute the steps only for Win
and Mac
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.
Addressed this in 537430b
[] | ||
); | ||
|
||
domainManager.registerEvent( |
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.
Empty function?
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 actually an event registration, for which no naming is required.
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.
Got it! Thanks
@nethip , I have addressed and committed all the required changes. Also, I have replied to all the comments. |
@mbhavi I think the preference to disable is still pending. |
@mbhavi I don't think the changes which I had proposed with There should be no reference of |
UpdateNotification.on(UpdateNotification.DIRTY_FILESAVE_CANCELLED, dirtyFileSaveCancelled); | ||
UpdateNotification.on(UpdateNotification.AUTOUPDATE_ERROR, handleAutoUpdateError); | ||
|
||
if(brackets.platform !== "linux") { |
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.
How about checking for the shell functions existence like setUpdateParamsAndQuit
, and if not present, just bail out?
src/utils/UpdateNotification.js
Outdated
@@ -333,6 +447,12 @@ define(function (require, exports, module) { | |||
var result = new $.Deferred(); | |||
var versionInfoUrl; | |||
|
|||
//AUTOUPDATE_UNITTESTING | |||
var updateJSONLocalhostURL = PreferencesManager.get("updateJSONLocalhostURL"); |
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 needs to be removed.
src/utils/UpdateNotification.js
Outdated
|
||
//If no checksum field is present then we're setting it to 0, just as a safety check, | ||
// although ideally this situation should never occur in releases post its introduction. | ||
var platformInfo = getPlatformInfo(), |
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.
If you want to retain this , you might want to move all of this to notifyGetUpdateInstaller
801a51e
to
bcb2a3e
Compare
…date, making AutoUpdate no-op for Linux, Replacing icons
src/utils/UpdateNotification.js
Outdated
@@ -61,6 +71,10 @@ define(function (require, exports, module) { | |||
// Data about available updates in the registry | |||
PreferencesManager.stateManager.definePreference("extensionUpdateInfo", "Array", []); | |||
|
|||
//Preference for hosting latest installer on a local server | |||
//AUTOUPDATE_UNITTESTING | |||
PreferencesManager.stateManager.definePreference("autoUpdate.testUrl", "string", ""); |
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.
Do you want to still retain this preference?
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.
@nethip , Yes we need to retain this preference, as this will be very much needed for unit testing purposes.
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.
Please have this preference in a separate branch. We can't be shipping with test URLs preference.
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.
@nethip, I have removed the preference from this branch. I will probably include the changes in a separate branch then, for unit testing purposes.
AppInit.appReady(function () { | ||
|
||
// Auto Update is supported on Win and Mac, as of now | ||
if (brackets.platform !== "linux") { |
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 think one of the review comments got missed here. You need to check if brackets.app.setUpdateParams
is registered or not. Only then run through the flow.
Thanks for addressing the review comments @mbhavi . I have added more comments. Please address those comments and I think we are good to merge from the dev perspective. |
LGTM. @mbhavi Thanks for this hugely requested PR 😄 ! Great job 💯 @ayushrathi15 We are waiting for the test results from your sanity testing. Please update this thread once you are done testing the private builds, so that we can go ahead with the merge. |
@mbhavi One last check. What if the node domain fails? Can we figure that out and bail out in your extension? |
} | ||
}) | ||
.fail(function() { | ||
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.
A console message message here would be good.
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.
…sole log message on node domain failure
This PR includes changes for Auto Update of Brackets.
The changes are with respect to:
ping @swmitra @nethip for review
The Auto Update workflow along with the screenshots is described below :
Any warnings or errors encountered during the worflow are reflected in the update bar.
Screenshots for one of the warnings is attached here. It corresponds to the scenario where user clicked on Restart button, but had dirty files to which he/she chose Cancel in File Save dialog. In this case, the update will happen on the next quit of Brackets, and the same is displayed to the user as a warning on update bar.
On MAC, instead of the installer, the update procedure is carried out by an update shell script. Rest everything is same for MAC, as above.