PMGR: Support VCS URLs to install from

Implements #2104
This commit is contained in:
Gina Häußge 2017-10-02 17:56:38 +02:00
parent 0f8f4579d6
commit c5e7212fa2
3 changed files with 49 additions and 5 deletions

View file

@ -40,6 +40,13 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
octoprint.plugin.EventHandlerPlugin):
ARCHIVE_EXTENSIONS = (".zip", ".tar.gz", ".tgz", ".tar")
# valid pip install URL schemes according to https://pip.pypa.io/en/stable/reference/pip_install/
URL_SCHEMES = ("http", "https", "git",
"git+http", "git+https", "git+ssh", "git+git",
"hg+http", "hg+https", "hg+static-http", "hg+ssh",
"svn", "svn+svn", "svn+http", "svn+https", "svn+ssh",
"bzr+http", "bzr+https", "bzr+ssh", "bzr+sftp", "bzr+ftp", "bzr+lp")
OPERATING_SYSTEMS = dict(windows=["win32"],
linux=lambda x: x.startswith("linux"),
@ -299,6 +306,9 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
def command_install(self, url=None, path=None, force=False, reinstall=None, dependency_links=False):
if url is not None:
if not any(map(lambda scheme: url.starts_with(scheme + "://"), self.URL_SCHEMES)):
raise ValueError("Invalid URL to pip install from")
source = url
source_type = "url"
already_installed_check = lambda line: url in line

View file

@ -239,23 +239,57 @@ $(function() {
};
self.invalidUrl = ko.pureComputed(function() {
// supported pip install URL schemes, according to https://pip.pypa.io/en/stable/reference/pip_install/
var allowedUrlSchemes = ["http", "https",
"git", "git+http", "git+https", "git+ssh", "git+git",
"hg+http", "hg+https", "hg+static-http", "hg+ssh",
"svn", "svn+svn", "svn+http", "svn+https", "svn+ssh",
"bzr+http", "bzr+https", "bzr+ssh", "bzr+sftp", "brz+ftp", "bzr+lp"];
var url = self.installUrl();
return url !== undefined && url.trim() != "" && !(_.startsWith(url.toLocaleLowerCase(), "http://") || _.startsWith(url.toLocaleLowerCase(), "https://"));
var lowerUrl = url !== undefined ? url.toLocaleLowerCase() : undefined;
var lowerUrlStartsWithScheme = function(scheme) {
return _.startsWith(lowerUrl, scheme + "://");
};
return url !== undefined && url.trim() !== ""
&& !(_.any(allowedUrlSchemes, lowerUrlStartsWithScheme));
});
self.enableUrlInstall = ko.pureComputed(function() {
var url = self.installUrl();
return self.enableManagement() && self.pipAvailable() && !self.safeMode() && self.online() && url !== undefined && url.trim() != "" && !self.invalidUrl();
return self.enableManagement()
&& self.pipAvailable()
&& !self.safeMode()
&& self.online()
&& url !== undefined
&& url.trim() !== ""
&& !self.invalidUrl();
});
self.invalidArchive = ko.pureComputed(function() {
var allowedArchiveExtensions = [".zip", ".tar.gz", ".tgz", ".tar"];
var name = self.uploadFilename();
return name !== undefined && !(_.endsWith(name.toLocaleLowerCase(), ".zip") || _.endsWith(name.toLocaleLowerCase(), ".tar.gz") || _.endsWith(name.toLocaleLowerCase(), ".tgz") || _.endsWith(name.toLocaleLowerCase(), ".tar"));
var lowerName = name !== undefined ? name.toLocaleLowerCase() : undefined;
var lowerNameHasExtension = function(extension) {
return _.endsWith(lowerName, extension);
};
return name !== undefined
&& !(_.any(allowedArchiveExtensions, lowerNameHasExtension));
});
self.enableArchiveInstall = ko.pureComputed(function() {
var name = self.uploadFilename();
return self.enableManagement() && self.pipAvailable() && !self.safeMode() && name !== undefined && name.trim() != "" && !self.invalidArchive();
return self.enableManagement()
&& self.pipAvailable()
&& !self.safeMode()
&& name !== undefined
&& name.trim() !== ""
&& !self.invalidArchive();
});
self.uploadElement.fileupload({

View file

@ -197,7 +197,7 @@
</div>
<button class="btn btn-primary span3" data-bind="enable: enableUrlInstall, css: {disabled: !enableUrlInstall()}, click: function() { if (enableUrlInstall()) { $root.installPlugin(); } }">{{ _('Install') }}</button>
</div>
<span class="help-block" data-bind="visible: invalidUrl">{{ _('This does not look like a valid "http://" or "https://" URL.') }}</span>
<span class="help-block" data-bind="visible: invalidUrl">{{ _('This does not look like a valid URL. Expected http, https or any of the <a href="%(url)s" target="_blank">supported VCS URLs</a>.', url='https://pip.pypa.io/en/stable/reference/pip_install/#vcs-support') }}</span>
</form>
<h4>{{ _('... from an uploaded archive') }}</h4>