diff --git a/docs/bundledplugins/softwareupdate.rst b/docs/bundledplugins/softwareupdate.rst index 763a0de5..904a3922 100644 --- a/docs/bundledplugins/softwareupdate.rst +++ b/docs/bundledplugins/softwareupdate.rst @@ -14,14 +14,14 @@ First Steps Out of the box the Software Update Plugin will be able to notify you of any updates that might be available for your OctoPrint installation or any plugins -that registered themselves with it. In order to also be able to update -your OctoPrint installation, you'll need to configure -at least OctoPrint's checkout folder, and you also should -configure the restart commands for OctoPrint and the whole server. +that registered themselves with it. In order for automatic restarts after updates +to work, you should configure the restart commands for OctoPrint and the whole server. -For configuring the plugin you'll need to go into OctoPrint's Settings Dialog, navigate to the -Software Upda.. _section therein and once you are there click on the little wrench icon in the -upper right corner. +Out of the box the plugin should already be ready to update your OctoPrint installation to current +stable release versions, but you can also switch to one of the available release candidate channels +or outright git commit tracking via the plugin's configuration dialog. To open this dialog, fire up OctoPrint's +Settings Dialog, navigate to the Software Update section therein and once you are there click on the little +wrench icon in the upper right corner. .. _fig-bundledplugins-softwareupdate-plugin-configuration: .. figure:: ../images/bundledplugins-softwareupdate-plugin-configuration.png @@ -32,31 +32,16 @@ upper right corner. There you can adjust the following settings: - * **OctoPrint checkout folder**: This should be the path to OctoPrint's git checkout folder (``/home/pi/OctoPrint`` - for OctoPi or `manual installs following the Raspberry Pi setup guide `_). - This must be set to allow updating from within OctoPrint - - .. note:: - - OctoPi releases 0.12.0 and later ship with this already setup for you. - - .. note:: - - **OctoPi 0.11.0 users**: Please also take a look at - `the note at the very end of this FAQ entry `_. - Due to a little issue in that OctoPi release 0.11.0 you might have to fix - the URL your OctoPrint checkout is using for updating. This can easily be - done by SSHing into your OctoPi instance and doing this:: - - cd ~/OctoPrint - git remote set-url origin https://github.com/foosel/OctoPrint.git - * **OctoPrint version tracking**: Whether you want to track OctoPrint *releases* or every *commit*. Usually you want to select "Release" here which is also the default, unless you are a developer. - * **OctoPrint Release Channel**: The release channel of OctoPrint to track for updates. If you only want stable versions, + * **OctoPrint Release Channel** (if tracking releases): The release channel of OctoPrint to track for updates. If you only want stable versions, select "Stable" here which is also the default. "Maintenance RCs" will also allow you to update to maintenance release candidates, "Devel RCs" will also allow you to update to development release candidates. If in doubt, leave it at "Stable". `Read more about Release Channels here `_. + * **OctoPrint checkout folder** (if tracking git commits): This must be the path to OctoPrint's git checkout folder + (``/home/pi/OctoPrint`` for OctoPi or `manual installs following the Raspberry Pi setup guide `_). + Note that since OctoPrint 1.3.6 you will no longer need to set this to be able to update to releases, only if you + want to be able to update against some bleeding edge git branch. * **Version cache TTL**: The "time to live" of the cache OctoPrint will use to temporarily persist the version information for the various components registered with the plugin, so that they don't have to be queried from the internet every time you load the page. Defaults to 24h, you usually shouldn't need to change that value. @@ -142,14 +127,13 @@ Configuring the Plugin # "octoprint" is reserved for OctoPrint octoprint: # this defines an version check that will check against releases - # published on OctoPrint's Github repository and an update method - # utilizing an (included) update script that will be run on - # OctoPrint's checkout folder + # published on OctoPrint's Github repository and pip as update method + # against the release archives on Github - this is the default type: github_release user: foosel repo: OctoPrint - update_script: '{python} "/path/to/octoprint-update.py" --python="{python}" "{folder}" "{target}"' - update_folder: /path/to/octoprint/checkout/folder + method: pip + pip: 'https://github.com/foosel/OctoPrint/archive/{target_version}.zip' # further checks may be define here @@ -249,6 +233,32 @@ Update methods :ref:`hook `. A python callable which performs the update, see below for details. +.. note:: + + To allow default configurations for multiple update methods, if more than one of + the above update method specific settings is set the one to use can be selected + by setting the property ``method`` to the method specific setting in question. + + **Example** + + The following example defines both ``pip`` and ``update_script``. By setting to + ``method`` to ``pip``, the Software Update plugin is instructed to use that as + update method. + + .. code-block:: + + plugins: + softwareupdate: + checks: + octoprint: + type: github_release + user: foosel + repo: OctoPrint + method: pip + pip: 'https://github.com/foosel/OctoPrint/archive/{target_version}.zip' + update_script: '{python} "/path/to/octoprint-update.py" --python="{python}" "{folder}" "{target}"' + checkout_folder: /path/to/octoprint/checkout/folder + .. _sec-bundledplugins-softwareupdate-configuration-patterns: Common configuration patterns @@ -268,6 +278,7 @@ plugin itself): user: foosel repo: OctoPrint branch: devel + method: update_script update_folder: /home/pi/OctoPrint Plugin installed via pip and hosted on Github under diff --git a/docs/images/bundledplugins-softwareupdate-plugin-configuration.png b/docs/images/bundledplugins-softwareupdate-plugin-configuration.png index 7d5a672c..ba13a997 100644 Binary files a/docs/images/bundledplugins-softwareupdate-plugin-configuration.png and b/docs/images/bundledplugins-softwareupdate-plugin-configuration.png differ diff --git a/src/octoprint/plugins/softwareupdate/__init__.py b/src/octoprint/plugins/softwareupdate/__init__.py index 256db832..630a8d26 100644 --- a/src/octoprint/plugins/softwareupdate/__init__.py +++ b/src/octoprint/plugins/softwareupdate/__init__.py @@ -41,6 +41,8 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, octoprint.plugin.EventHandlerPlugin): COMMIT_TRACKING_TYPES = ("github_commit", "bitbucket_commit") + + DATA_FORMAT_VERSION = "v2" def __init__(self): self._update_in_progress = False @@ -216,13 +218,18 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, def get_settings_defaults(self): update_script = os.path.join(self._basefolder, "scripts", "update-octoprint.py") + default_update_script = "{{python}} \"{update_script}\" --branch={{branch}} " \ + "--force={{force}} \"{{folder}}\" {{target}}".format(update_script=update_script) + return { "checks": { "octoprint": { "type": "github_release", "user": "foosel", "repo": "OctoPrint", - "update_script": "{{python}} \"{update_script}\" --branch={{branch}} --force={{force}} \"{{folder}}\" {{target}}".format(update_script=update_script), + "method": "pip", + "pip": "https://github.com/foosel/OctoPrint/archive/{target_version}.zip", + "update_script": default_update_script, "restart": "octoprint", "stable_branch": dict(branch="master", commitish=["master"], name="Stable"), "prerelease_branches": [dict(branch="rc/maintenance", @@ -302,12 +309,13 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, if "octoprint" in checks: check = checks["octoprint"] update_type = check.get("type", None) + update_method = self._get_update_method("octoprint", check) checkout_folder = check.get("checkout_folder", None) update_folder = check.get("update_folder", None) prerelease = check.get("prerelease", False) prerelease_channel = check.get("prerelease_channel", None) else: - update_type = checkout_folder = update_folder = prerelease_channel = None + update_type = update_method = checkout_folder = update_folder = prerelease_channel = None prerelease = False defaults = dict( @@ -315,6 +323,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, checks=dict( octoprint=dict( type=update_type, + method=update_method, checkout_folder=checkout_folder, update_folder=update_folder, prerelease=prerelease, @@ -332,10 +341,30 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, self._settings.set(["checks", "octoprint", "update_folder"], None, defaults=defaults, force=True) updated_octoprint_check_config = True - if "octoprint_type" in data and data["octoprint_type"] in ("github_release", "git_commit"): - self._settings.set(["checks", "octoprint", "type"], data["octoprint_type"], defaults=defaults, force=True) - updated_octoprint_check_config = True + if "octoprint_type" in data: + octoprint_type = data["octoprint_type"] + + if octoprint_type == "github_release": + self._settings.set(["checks", "octoprint", "type"], octoprint_type, defaults=defaults, force=True) + self._settings.set(["checks", "octoprint", "method"], "pip", defaults=defaults, force=True) + updated_octoprint_check_config = True + elif octoprint_type == "git_commit": + self._settings.set(["checks", "octoprint", "type"], octoprint_type, defaults=defaults, force=True) + self._settings.set(["checks", "octoprint", "method"], "update_script", defaults=defaults, force=True) + updated_octoprint_check_config = True + + if "octoprint_release_channel" in data: + prerelease_branches = self._settings.get(["checks", "octoprint", "prerelease_branches"]) + if prerelease_branches and data["octoprint_release_channel"] in [x["branch"] for x in prerelease_branches]: + self._settings.set(["checks", "octoprint", "prerelease"], True, defaults=defaults, force=True) + self._settings.set(["checks", "octoprint", "prerelease_channel"], data["octoprint_release_channel"], + defaults=defaults, force=True) + else: + self._settings.set(["checks", "octoprint", "prerelease"], False, defaults=defaults, force=True) + self._settings.set(["checks", "octoprint", "prerelease_channel"], None, defaults=defaults, force=True) + updated_octoprint_check_config = True + if updated_octoprint_check_config: self._refresh_configured_checks = True try: @@ -344,22 +373,23 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, pass self._version_cache_dirty = True - if "octoprint_release_channel" in data: - prerelease_branches = self._settings.get(["checks", "octoprint", "prerelease_branches"]) - if prerelease_branches and data["octoprint_release_channel"] in [x["branch"] for x in prerelease_branches]: - self._settings.set(["checks", "octoprint", "prerelease"], True, defaults=defaults, force=True) - self._settings.set(["checks", "octoprint", "prerelease_channel"], data["octoprint_release_channel"], defaults=defaults, force=True) - self._refresh_configured_checks = True - else: - self._settings.set(["checks", "octoprint", "prerelease"], False, defaults=defaults, force=True) - self._settings.set(["checks", "octoprint", "prerelease_channel"], None, defaults=defaults, force=True) - self._refresh_configured_checks = True - def get_settings_version(self): - return 5 + return 6 def on_settings_migrate(self, target, current=None): + if current is None or current < 6: + # up until & including config version 5 we didn't set the method parameter for the octoprint check + # configuration + + configured_checks = self._settings.get(["checks"], incl_defaults=False) + if configured_checks is not None and "octoprint" in configured_checks: + octoprint_check = dict(configured_checks["octoprint"]) + + if not "method" in octoprint_check and octoprint_check.get("type") == "git_commit": + defaults = dict(plugins=dict(softwareupdate=dict(checks=dict(octoprint=dict(method="pip"))))) + self._settings.set(["checks", "octoprint", "method"], "update_script", defaults=defaults) + if current == 4: # config version 4 didn't correctly remove the old settings for octoprint_restart_command # and environment_restart_command @@ -504,6 +534,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, hash.update(",".join(targets)) hash.update(str(self._version_cache_timestamp)) hash.update(str(self._connectivity_checker.online)) + hash.update(self.DATA_FORMAT_VERSION) return hash.hexdigest() def condition(): @@ -563,7 +594,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, checks = self._get_configured_checks() check = checks.get("octoprint", None) checkout_folder = self._get_octoprint_checkout_folder(checks=checks) - return check and "update_script" in check and not checkout_folder + return check and "method" in check and check["method"] == "update_script" and not checkout_folder ##~~ EventHandlerPlugin API @@ -667,6 +698,9 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, releaseNotes=release_notes, online=target_online, error=target_error) + + if target == "octoprint" and "released_version" in populated_check: + information[target]["released_version"] = populated_check["released_version"] if self._version_cache_dirty: self._save_version_cache() @@ -989,24 +1023,22 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, # we compare versions fully, not just the base so that we see a difference # between RCs + stable for the same version release result["force_base"] = False + + if check.get("prerelease", None): + # we are tracking prereleases => we want to be on the correct prerelease channel/branch + channel = check.get("prerelease_channel", None) + if channel: + # if we have a release channel, we also set our update_branch here to our release channel + # in case it's not already set + result["update_branch"] = check.get("update_branch", channel) + + else: + # we are not tracking prereleases, but aren't on the stable branch either => switch back + # to stable branch on update + result["update_branch"] = check.get("update_branch", stable_branch) if check.get("update_script", None): - # if we are using the update_script, we need to set our update_branch - - if check.get("prerelease", None): - # we are tracking prereleases => we want to be on the correct prerelease channel/branch - channel = check.get("prerelease_channel", None) - if channel: - # if we have a release channel, we also set our update_branch here to our release channel - # in case it's not already set - result["update_branch"] = check.get("update_branch", channel) - - else: - # we are not tracking prereleases, but aren't on the stable branch either => switch back - # to stable branch on update - result["update_branch"] = check.get("update_branch", stable_branch) - - # we also force an exact version + # we force an exact version result["force_exact_version"] = True if BRANCH != result.get("prerelease_channel"): @@ -1017,6 +1049,10 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, # branch of the release channel - unequality means we might have to handle # a downgrade result["release_compare"] = "python_unequal" + + elif check.get("pip", None): + # we force python unequality check for pip installs, to be able to downgrade + result["release_compare"] = "python_unequal" else: result["displayName"] = to_unicode(check.get("displayName"), errors="replace") diff --git a/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js b/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js index 9b6b1f3e..8b5a3c87 100644 --- a/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js +++ b/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js @@ -108,8 +108,15 @@ $(function() { self.checking = ko.observable(false); - self.octoprintUnconfigured = ko.observable(); - self.octoprintUnreleased = ko.observable(); + self.octoprintReleasedVersion = ko.observable(); + + self.octoprintUnconfigured = ko.pureComputed(function() { + return self.error_checkoutFolder(); + }); + self.octoprintUnreleased = ko.pureComputed(function() { + return self.settings.settings.plugins.softwareupdate.octoprint_type() === "github_release" + && !self.octoprintReleasedVersion(); + }); self.cacheTimestamp = ko.observable(); self.cacheTimestampText = ko.pureComputed(function() { @@ -120,9 +127,18 @@ $(function() { self.config_notifyUsers = ko.observable(); self.config_checkoutFolder = ko.observable(); self.config_checkType = ko.observable(); - self.config_updateMethod = ko.observable(); self.config_releaseChannel = ko.observable(); + self.error_checkoutFolder = ko.pureComputed(function() { + return self.config_checkType() === "git_commit" + && (!self.config_checkoutFolder() || self.config_checkoutFolder().trim() === ''); + }); + + self.enable_configSave = ko.pureComputed(function() { + return self.config_checkType() === "github_release" + || (self.config_checkType() === "git_commit" && !self.error_checkoutFolder()); + }); + self.configurationDialog = undefined; self.confirmationDialog = undefined; self._updateClicked = false; @@ -137,8 +153,8 @@ $(function() { { "name": function(a, b) { // sorts ascending, puts octoprint first - if (a.key.toLocaleLowerCase() == "octoprint") return -1; - if (b.key.toLocaleLowerCase() == "octoprint") return 1; + if (a.key.toLocaleLowerCase() === "octoprint") return -1; + if (b.key.toLocaleLowerCase() === "octoprint") return 1; if (a.displayName.toLocaleLowerCase() < b.displayName.toLocaleLowerCase()) return -1; if (a.displayName.toLocaleLowerCase() > b.displayName.toLocaleLowerCase()) return 1; @@ -211,9 +227,9 @@ $(function() { softwareupdate: { cache_ttl: parseInt(self.config_cacheTtl()), notify_users: self.config_notifyUsers(), - octoprint_checkout_folder: self.config_checkoutFolder(), octoprint_type: self.config_checkType(), - octoprint_release_channel: self.config_releaseChannel() + octoprint_release_channel: self.config_releaseChannel(), + octoprint_checkout_folder: self.config_checkoutFolder() } } }; @@ -231,15 +247,8 @@ $(function() { }; self._copyConfig = function() { - var updateMethod = self.settings.settings.plugins.softwareupdate.octoprint_method(); - - var availableCheckTypes = []; - if (updateMethod == "update_script" || updateMethod == "python") { - availableCheckTypes = [{"key": "github_release", "name": gettext("Release")}, + var availableCheckTypes = [{"key": "github_release", "name": gettext("Release")}, {"key": "git_commit", "name": gettext("Commit")}]; - } else { - availableCheckTypes = []; - } self.config_availableCheckTypes(availableCheckTypes); var availableReleaseChannels = []; @@ -248,12 +257,12 @@ $(function() { }); self.config_availableReleaseChannels(availableReleaseChannels); - self.config_updateMethod(updateMethod); self.config_cacheTtl(self.settings.settings.plugins.softwareupdate.cache_ttl()); self.config_notifyUsers(self.settings.settings.plugins.softwareupdate.notify_users()); - self.config_checkoutFolder(self.settings.settings.plugins.softwareupdate.octoprint_checkout_folder()); + self.config_checkType(self.settings.settings.plugins.softwareupdate.octoprint_type()); self.config_releaseChannel(self.settings.settings.plugins.softwareupdate.octoprint_release_channel()); + self.config_checkoutFolder(self.settings.settings.plugins.softwareupdate.octoprint_checkout_folder()); }; self._copyConfigBack = function() { @@ -268,13 +277,13 @@ $(function() { _.each(data.information, function(value, key) { value["key"] = key; - if (!value.hasOwnProperty("displayName") || value.displayName == "") { + if (!value.hasOwnProperty("displayName") || value.displayName === "") { value.displayName = value.key; } - if (!value.hasOwnProperty("displayVersion") || value.displayVersion == "") { + if (!value.hasOwnProperty("displayVersion") || value.displayVersion === "") { value.displayVersion = value.information.local.name; } - if (!value.hasOwnProperty("releaseNotes") || value.releaseNotes == "") { + if (!value.hasOwnProperty("releaseNotes") || value.releaseNotes === "") { value.releaseNotes = undefined; } @@ -292,27 +301,11 @@ $(function() { self.versions.updateItems(versions); var octoprint = data.information["octoprint"]; - if (octoprint && octoprint.hasOwnProperty("check")) { - var check = octoprint.check; - if (check["released_version"] === false && check["type"] == "github_release") { - self.octoprintUnreleased(true); - } else { - self.octoprintUnreleased(false); - } - - var checkoutFolder = (check["checkout_folder"] || "").trim(); - var updateFolder = (check["update_folder"] || "").trim(); - var needsFolder = check["update_script"] || false; - if (needsFolder && checkoutFolder == "" && updateFolder == "") { - self.octoprintUnconfigured(true); - } else { - self.octoprintUnconfigured(false); - } - } + self.octoprintReleasedVersion(!octoprint || octoprint.released_version); if (!self.loginState.isAdmin() && !self.settings.settings.plugins.softwareupdate.notify_users()) return; - if (data.status == "updateAvailable" || data.status == "updatePossible") { + if (data.status === "updateAvailable" || data.status === "updatePossible") { var text = "
" + gettext("There are updates available for the following components:"); text += "
    "; @@ -343,7 +336,7 @@ $(function() { var eventListeners = {}; var singleButtonNotify = false; - if (data.status == "updatePossible" && self.loginState.isAdmin()) { + if (data.status === "updatePossible" && self.loginState.isAdmin()) { // if update is possible and user is admin, add action buttons for ignore and update options["confirm"] = { confirm: true, @@ -391,7 +384,7 @@ $(function() { if ((ignoreSeen || !self._hasNotificationBeenSeen(data.information)) && !OctoPrint.coreui.wizardOpen) { self._showPopup(options, eventListeners, singleButtonNotify); } - } else if (data.status == "current") { + } else if (data.status === "current") { if (showIfNothingNew) { self._showPopup({ title: gettext("Everything is up-to-date"), @@ -473,7 +466,7 @@ $(function() { if (!Modernizr.localstorage) return false; - if (localStorage["plugin.softwareupdate.seen_information"] == undefined) + if (localStorage["plugin.softwareupdate.seen_information"] === undefined) return false; var knownData = JSON.parse(localStorage["plugin.softwareupdate.seen_information"]); @@ -489,7 +482,7 @@ $(function() { var hasBeenSeen = true; _.each(freshData, function(value, key) { - if (!_.has(userData, key) || userData[key] != freshData[key]) { + if (!_.has(userData, key) || userData[key] !== freshData[key]) { hasBeenSeen = false; } }); @@ -610,10 +603,10 @@ $(function() { }; self.onBeforeWizardTabChange = function(next, current) { - if (next && _.startsWith(next, "wizard_plugin_softwareupdate")) { + if (next && next === "#wizard_plugin_softwareupdate") { // switching to the plugin wizard tab self._copyConfig(); - } else if (current && _.startsWith(current, "wizard_plugin_softwareupdate")) { + } else if (current && current === "#wizard_plugin_softwareupdate") { // switching away from the plugin wizard tab self._copyConfigBack(); } @@ -658,7 +651,7 @@ $(function() { }; self.onDataUpdaterPluginMessage = function(plugin, data) { - if (plugin != "softwareupdate") { + if (plugin !== "softwareupdate") { return; } @@ -749,7 +742,7 @@ $(function() { restartType = messageData.restart_type; text = gettext("The update finished successfully, please restart OctoPrint now."); - if (restartType == "environment") { + if (restartType === "environment") { text = gettext("The update finished successfully, please reboot the server now."); } @@ -770,7 +763,7 @@ $(function() { case "restart_failed": { restartType = messageData.restart_type; text = gettext("Restarting OctoPrint failed, please restart it manually. You might also want to consult the log file on what went wrong here."); - if (restartType == "environment") { + if (restartType === "environment") { text = gettext("Rebooting the server failed, please reboot it manually. You might also want to consult the log file on what went wrong here."); } @@ -827,7 +820,7 @@ $(function() { } } - if (options != undefined) { + if (options !== undefined) { self._showPopup(options); } }; @@ -837,7 +830,7 @@ $(function() { "'.*?' does not exist -- can't clean it"]; self._forcedStdoutLine = new RegExp(self._forcedStdoutPatterns.join("|")); self._preprocessLine = function(line) { - if (line.stream == "stderr" && line.line.match(self._forcedStdoutLine)) { + if (line.stream === "stderr" && line.line.match(self._forcedStdoutLine)) { line.stream = "stdout"; } return line; diff --git a/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/checkoutFolder.jinja2 b/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/checkoutFolder.jinja2 index b45c8655..906cc227 100644 --- a/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/checkoutFolder.jinja2 +++ b/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/checkoutFolder.jinja2 @@ -1,6 +1,7 @@ -
    +
    + {{ _('This needs to be set if you select commit based version tracking.') }}
    diff --git a/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/releaseChannel.jinja2 b/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/releaseChannel.jinja2 index 6133e9b5..57ec4151 100644 --- a/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/releaseChannel.jinja2 +++ b/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/releaseChannel.jinja2 @@ -1,4 +1,4 @@ -
    +
    diff --git a/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/versionTracking.jinja2 b/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/versionTracking.jinja2 index d53d21a6..a57a81a7 100644 --- a/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/versionTracking.jinja2 +++ b/src/octoprint/plugins/softwareupdate/templates/snippets/plugins/softwareupdate/versionTracking.jinja2 @@ -1,4 +1,4 @@ -
    +
    diff --git a/src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2 b/src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2 index aa6c9e50..a8a60fed 100644 --- a/src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2 +++ b/src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2 @@ -76,8 +76,8 @@
    diff --git a/src/octoprint/plugins/softwareupdate/templates/softwareupdate_wizard.jinja2 b/src/octoprint/plugins/softwareupdate/templates/softwareupdate_wizard.jinja2 index d840a292..eabb1cef 100644 --- a/src/octoprint/plugins/softwareupdate/templates/softwareupdate_wizard.jinja2 +++ b/src/octoprint/plugins/softwareupdate/templates/softwareupdate_wizard.jinja2 @@ -1,13 +1,14 @@

    {{ _('Software Update') }}

    {% trans %}

    - OctoPrint can update itself via git, but it needs to know its checkout folder and the way - it should track available updates in order to be able to do that. You can configure that here. + By default, OctoPrint will update itself via pip to published releases. OctoPrint can + also update itself via git to arbitrary development branches you need to check out manually. + If you want to do that though it needs to know its checkout folder. You can configure that here.

    {% endtrans %} - {% include "snippets/plugins/softwareupdate/checkoutFolder.jinja2" %} {% include "snippets/plugins/softwareupdate/versionTracking.jinja2" %} + {% include "snippets/plugins/softwareupdate/checkoutFolder.jinja2" %} {% trans %}

    diff --git a/src/octoprint/plugins/softwareupdate/updaters/pip.py b/src/octoprint/plugins/softwareupdate/updaters/pip.py index 3c0e9022..8605e2b3 100644 --- a/src/octoprint/plugins/softwareupdate/updaters/pip.py +++ b/src/octoprint/plugins/softwareupdate/updaters/pip.py @@ -15,6 +15,8 @@ from .. import exceptions logger = logging.getLogger("octoprint.plugins.softwareupdate.updaters.pip") console_logger = logging.getLogger("octoprint.plugins.softwareupdate.updaters.pip.console") +_ALREADY_INSTALLED = "Requirement already satisfied (use --upgrade to upgrade)" + _pip_callers = dict() _pip_version_dependency_links = pkg_resources.parse_version("1.5") @@ -35,7 +37,7 @@ def _get_pip_caller(command=None): return _pip_callers[key] -def perform_update(target, check, target_version, log_cb=None, online=True): +def perform_update(target, check, target_version, log_cb=None, online=True, force=False): pip_command = None if "pip_command" in check: pip_command = check["pip_command"] @@ -66,10 +68,10 @@ def perform_update(target, check, target_version, log_cb=None, online=True): pip_caller.on_log_stdout = _log_stdout pip_caller.on_log_stderr = _log_stderr - install_arg = check["pip"].format(target_version=target_version) + install_arg = check["pip"].format(target_version=target_version, target=target_version) logger.debug(u"Target: %s, executing pip install %s" % (target, install_arg)) - pip_args = ["install", check["pip"].format(target_version=target_version, target=target_version)] + pip_args = ["install", install_arg] if "dependency_links" in check and check["dependency_links"]: pip_args += ["--process-dependency-links"] @@ -77,12 +79,17 @@ def perform_update(target, check, target_version, log_cb=None, online=True): returncode, stdout, stderr = pip_caller.execute(*pip_args) if returncode != 0: raise exceptions.UpdateError("Error while executing pip install", (stdout, stderr)) + + if not force and any(map(lambda x: x.strip().startswith(_ALREADY_INSTALLED) and (install_arg in x or install_arg in x.lower()), stdout)): + logger.debug(u"Looks like we were already installed in this version. Forcing a reinstall.") + force = True - logger.debug(u"Target: %s, executing pip install %s --ignore-reinstalled --force-reinstall --no-deps" % (target, install_arg)) - pip_args += ["--ignore-installed", "--force-reinstall", "--no-deps"] - - returncode, stdout, stderr = pip_caller.execute(*pip_args) - if returncode != 0: - raise exceptions.UpdateError("Error while executing pip install --force-reinstall", (stdout, stderr)) + if force: + logger.debug(u"Target: %s, executing pip install %s --ignore-reinstalled --force-reinstall --no-deps" % (target, install_arg)) + pip_args += ["--ignore-installed", "--force-reinstall", "--no-deps"] + + returncode, stdout, stderr = pip_caller.execute(*pip_args) + if returncode != 0: + raise exceptions.UpdateError("Error while executing pip install --force-reinstall", (stdout, stderr)) return "ok" diff --git a/src/octoprint/static/js/app/viewmodels/wizard.js b/src/octoprint/static/js/app/viewmodels/wizard.js index fbc2e37b..72c965ed 100644 --- a/src/octoprint/static/js/app/viewmodels/wizard.js +++ b/src/octoprint/static/js/app/viewmodels/wizard.js @@ -34,6 +34,9 @@ $(function() { } callViewModels(self.allViewModels, "onWizardShow"); + + callViewModels(self.allViewModels, "onBeforeWizardTabChange", [OCTOPRINT_INITIAL_WIZARD, undefined]); + callViewModels(self.allViewModels, "onAfterWizardTabChange", [OCTOPRINT_INITIAL_WIZARD]); }); }; diff --git a/src/octoprint/templates/initscript.jinja2 b/src/octoprint/templates/initscript.jinja2 index daacfde4..722830bf 100644 --- a/src/octoprint/templates/initscript.jinja2 +++ b/src/octoprint/templates/initscript.jinja2 @@ -44,4 +44,12 @@ {% else %} var OCTOPRINT_INITIAL_TAB = undefined; {% endif %} + + {% if templates.wizard and templates.wizard.order %} + {% set first_tab = templates.wizard.order[0] %} + {% set entry, data = templates.wizard.entries[first_tab] %} + var OCTOPRINT_INITIAL_WIZARD = "#{{ data._div }}"; + {% else %} + var OCTOPRINT_INITIAL_WIZARD = undefined; + {% endif %}