Environment detection & logging on startup
Incl. OctoPi version & RPi model through bundled plugin that only gets loaded if OctoPi is detected.
This commit is contained in:
parent
0bb343e1d3
commit
b2d70de144
19 changed files with 494 additions and 53 deletions
2
setup.py
2
setup.py
|
|
@ -40,7 +40,7 @@ INSTALL_REQUIRES = [
|
|||
"pkginfo>=1.2.1,<1.3",
|
||||
"requests>=2.18.4,<3",
|
||||
"semantic_version>=2.4.2,<2.5",
|
||||
"psutil>=5.4.0,<6",
|
||||
"psutil>=5.4.1,<6",
|
||||
"Click>=6.2,<6.3",
|
||||
"awesome-slugify>=1.6.5,<1.7",
|
||||
"feedparser>=5.2.1,<5.3",
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ def init_platform(basedir, configfile, use_logging_file=True, logging_file=None,
|
|||
uncaught_handler=None, safe_mode=False, ignore_blacklist=False, after_preinit_logging=None,
|
||||
after_settings=None, after_logging=None, after_safe_mode=None,
|
||||
after_event_manager=None, after_connectivity_checker=None,
|
||||
after_plugin_manager=None):
|
||||
after_plugin_manager=None, after_environment_detector=None):
|
||||
kwargs = dict()
|
||||
|
||||
logger, recorder = preinit_logging(debug, verbosity, uncaught_logger, uncaught_handler)
|
||||
|
|
@ -115,8 +115,14 @@ def init_platform(basedir, configfile, use_logging_file=True, logging_file=None,
|
|||
|
||||
if callable(after_plugin_manager):
|
||||
after_plugin_manager(**kwargs)
|
||||
|
||||
environment_detector = init_environment_detector(plugin_manager)
|
||||
kwargs["environment_detector"] = environment_detector
|
||||
|
||||
if callable(after_environment_detector):
|
||||
after_environment_detector(**kwargs)
|
||||
|
||||
return settings, logger, safe_mode, event_manager, connectivity_checker, plugin_manager
|
||||
return settings, logger, safe_mode, event_manager, connectivity_checker, plugin_manager, environment_detector
|
||||
|
||||
|
||||
def init_settings(basedir, configfile):
|
||||
|
|
@ -522,6 +528,10 @@ def init_connectivity_checker(settings, event_manager):
|
|||
return connectivityChecker
|
||||
|
||||
|
||||
def init_environment_detector(plugin_manager):
|
||||
from octoprint.environment import EnvironmentDetector
|
||||
return EnvironmentDetector(plugin_manager)
|
||||
|
||||
#~~ server main method
|
||||
|
||||
def main():
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ def run_server(basedir, configfile, host, port, debug, allow_root, logging_confi
|
|||
"https://urllib3.readthedocs.org/en/latest/security.html#openssl-pyopenssl")
|
||||
logger.info(get_divider_line("*"))
|
||||
|
||||
def log_register_rollover(safe_mode=None, plugin_manager=None, **kwargs):
|
||||
def log_register_rollover(safe_mode=None, plugin_manager=None, environment_detector=None, **kwargs):
|
||||
from octoprint.logging import get_handler, log_to_handler, get_divider_line
|
||||
from octoprint.logging.handlers import OctoPrintLogHandler
|
||||
|
||||
|
|
@ -67,22 +67,24 @@ def run_server(basedir, configfile, host, port, debug, allow_root, logging_confi
|
|||
if safe_mode:
|
||||
_log("SAFE MODE is active. Third party plugins are disabled!")
|
||||
plugin_manager.log_all_plugins(only_to_handler=handler)
|
||||
environment_detector.log_detected_environment(only_to_handler=handler)
|
||||
_log(get_divider_line("-"))
|
||||
|
||||
OctoPrintLogHandler.registerRolloverCallback(rollover_callback)
|
||||
|
||||
try:
|
||||
settings, _, safe_mode, event_manager, \
|
||||
connectivity_checker, plugin_manager = init_platform(basedir,
|
||||
configfile,
|
||||
logging_file=logging_config,
|
||||
debug=debug,
|
||||
verbosity=verbosity,
|
||||
uncaught_logger=__name__,
|
||||
safe_mode=safe_mode,
|
||||
ignore_blacklist=ignore_blacklist,
|
||||
after_safe_mode=log_startup,
|
||||
after_plugin_manager=log_register_rollover)
|
||||
components = init_platform(basedir, configfile,
|
||||
logging_file=logging_config,
|
||||
debug=debug,
|
||||
verbosity=verbosity,
|
||||
uncaught_logger=__name__,
|
||||
safe_mode=safe_mode,
|
||||
ignore_blacklist=ignore_blacklist,
|
||||
after_safe_mode=log_startup,
|
||||
after_plugin_manager=log_register_rollover)
|
||||
|
||||
settings, _, safe_mode, event_manager, connectivity_checker, plugin_manager, environment_detector = components
|
||||
|
||||
except FatalStartupError as e:
|
||||
click.echo(e.message, err=True)
|
||||
click.echo("There was a fatal error starting up OctoPrint.", err=True)
|
||||
|
|
@ -92,6 +94,7 @@ def run_server(basedir, configfile, host, port, debug, allow_root, logging_confi
|
|||
plugin_manager=plugin_manager,
|
||||
event_manager=event_manager,
|
||||
connectivity_checker=connectivity_checker,
|
||||
environment_detector=environment_detector,
|
||||
host=host,
|
||||
port=port,
|
||||
debug=debug,
|
||||
|
|
|
|||
133
src/octoprint/environment.py
Normal file
133
src/octoprint/environment.py
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import copy
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import threading
|
||||
import yaml
|
||||
|
||||
import psutil
|
||||
|
||||
from octoprint.plugin import EnvironmentDetectionPlugin
|
||||
from octoprint.util import get_formatted_size
|
||||
from octoprint.util.platform import get_os
|
||||
|
||||
class EnvironmentDetector(object):
|
||||
|
||||
def __init__(self, plugin_manager):
|
||||
self._plugin_manager = plugin_manager
|
||||
|
||||
self._cache = None
|
||||
self._cache_lock = threading.RLock()
|
||||
|
||||
self._environment_plugins = self._plugin_manager.get_implementations(EnvironmentDetectionPlugin)
|
||||
|
||||
self._logger = logging.getLogger(__name__)
|
||||
|
||||
@property
|
||||
def environment(self):
|
||||
with self._cache_lock:
|
||||
if self._cache is None:
|
||||
self.run_detection()
|
||||
return copy.deepcopy(self._cache)
|
||||
|
||||
def run_detection(self, notify_plugins=True):
|
||||
environment = dict()
|
||||
environment["os"] = self._detect_os()
|
||||
environment["python"] = self._detect_python()
|
||||
environment["hardware"] = self._detect_hardware()
|
||||
|
||||
plugin_result = self._detect_from_plugins()
|
||||
if plugin_result:
|
||||
environment["plugins"] = plugin_result
|
||||
|
||||
with self._cache_lock:
|
||||
self._cache = environment
|
||||
|
||||
if notify_plugins:
|
||||
self.notify_plugins()
|
||||
|
||||
return environment
|
||||
|
||||
def _detect_os(self):
|
||||
return dict(id=get_os(),
|
||||
platform=sys.platform)
|
||||
|
||||
def _detect_python(self):
|
||||
result = dict()
|
||||
|
||||
# determine python version
|
||||
result["version"] = platform.python_version()
|
||||
|
||||
# determine if we are running from a virtual environment
|
||||
if hasattr(sys, "real_prefix") or (hasattr(sys, "base_prefix") and os.path.realpath(sys.prefix) != os.path.realpath(sys.base_prefix)):
|
||||
result["virtualenv"] = sys.prefix
|
||||
|
||||
# try to find pip version
|
||||
try:
|
||||
import pip
|
||||
result["pip"] = pip.__version__
|
||||
except:
|
||||
result["pip"] = "unknown"
|
||||
|
||||
return result
|
||||
|
||||
def _detect_hardware(self):
|
||||
return dict(cores=psutil.cpu_count(),
|
||||
freq=psutil.cpu_freq().max,
|
||||
ram=get_formatted_size(psutil.virtual_memory().total))
|
||||
|
||||
def _detect_from_plugins(self):
|
||||
result = dict()
|
||||
|
||||
for implementation in self._environment_plugins:
|
||||
try:
|
||||
additional = implementation.get_additional_environment()
|
||||
if additional is not None and isinstance(additional, dict) and len(additional):
|
||||
result[implementation._identifier] = additional
|
||||
except:
|
||||
self._logger.exception("Error while fetching additional "
|
||||
"environment data from plugin {}".format(implementation._identifier))
|
||||
|
||||
return result
|
||||
|
||||
def log_detected_environment(self, only_to_handler=None):
|
||||
def _log(message, level=logging.INFO):
|
||||
if only_to_handler is not None:
|
||||
import octoprint.logging
|
||||
octoprint.logging.log_to_handler(self._logger, only_to_handler, level, message, [])
|
||||
else:
|
||||
self._logger.log(level, message)
|
||||
|
||||
_log(self._format())
|
||||
|
||||
def _format(self):
|
||||
with self._cache_lock:
|
||||
if self._cache is None:
|
||||
self.run_detection()
|
||||
environment = copy.deepcopy(self._cache)
|
||||
|
||||
dumped_environment = yaml.safe_dump(environment,
|
||||
default_flow_style=False,
|
||||
indent=" ",
|
||||
allow_unicode=True).strip()
|
||||
environment_lines = "\n".join(map(lambda l: "| {}".format(l), dumped_environment.split("\n")))
|
||||
return u"Detected environment is Python {} under {} ({}). Details:\n{}".format(environment["python"]["version"],
|
||||
environment["os"]["id"].title(),
|
||||
environment["os"]["platform"],
|
||||
environment_lines)
|
||||
|
||||
def notify_plugins(self):
|
||||
with self._cache_lock:
|
||||
if self._cache is None:
|
||||
self.run_detection(notify_plugins=False)
|
||||
environment = copy.deepcopy(self._cache)
|
||||
|
||||
for implementation in self._environment_plugins:
|
||||
try:
|
||||
implementation.on_environment_detected(environment)
|
||||
except:
|
||||
self._logger.exception("Error while sending environment "
|
||||
"detection result to plugin {}".format(implementation._identifier))
|
||||
|
|
@ -91,7 +91,8 @@ def plugin_manager(init=False, plugin_folders=None, plugin_types=None, plugin_en
|
|||
else:
|
||||
if init:
|
||||
if plugin_types is None:
|
||||
plugin_types = [StartupPlugin,
|
||||
plugin_types = [EnvironmentDetectionPlugin,
|
||||
StartupPlugin,
|
||||
ShutdownPlugin,
|
||||
TemplatePlugin,
|
||||
SettingsPlugin,
|
||||
|
|
|
|||
|
|
@ -105,6 +105,16 @@ class ReloadNeedingPlugin(Plugin):
|
|||
Mixin for plugin types that need a reload of the UI after enabling/disabling them.
|
||||
"""
|
||||
|
||||
|
||||
class EnvironmentDetectionPlugin(OctoPrintPlugin, RestartNeedingPlugin):
|
||||
|
||||
def get_additional_environment(self):
|
||||
pass
|
||||
|
||||
def on_environment_detected(self, environment, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class StartupPlugin(OctoPrintPlugin, SortablePlugin):
|
||||
"""
|
||||
The ``StartupPlugin`` allows hooking into the startup of OctoPrint. It can be used to start up additional services
|
||||
|
|
|
|||
154
src/octoprint/plugins/octopi_support/__init__.py
Normal file
154
src/octoprint/plugins/octopi_support/__init__.py
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# coding=utf-8
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
__copyright__ = "Copyright (C) 2017 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
||||
|
||||
import flask
|
||||
import os
|
||||
|
||||
import octoprint.plugin
|
||||
|
||||
_OCTOPI_VERSION_PATH = "/etc/octopi_version"
|
||||
_CPUINFO_PATH = "/proc/cpuinfo"
|
||||
|
||||
# based on https://elinux.org/RPi_HardwareHistory#Which_Pi_have_I_got.3F
|
||||
_RPI_REVISION_MAP = {
|
||||
"Beta": "1B (Beta)",
|
||||
"0002": "1B",
|
||||
"0003": "1B",
|
||||
"0004": "1B",
|
||||
"0005": "1B",
|
||||
"0006": "1B",
|
||||
"0007": "1A",
|
||||
"0008": "1A",
|
||||
"0009": "1A",
|
||||
"000d": "1B",
|
||||
"000e": "1B",
|
||||
"000f": "1B",
|
||||
"0010": "B+",
|
||||
"0011": "CM1",
|
||||
"0012": "A+",
|
||||
"0013": "B+",
|
||||
"0014": "CM1",
|
||||
"0015": "A+",
|
||||
"a01040": "2B",
|
||||
"a01041": "2B",
|
||||
"a21041": "2B",
|
||||
"a22042": "2B",
|
||||
"900021": "A+",
|
||||
"900032": "B+",
|
||||
"900092": "Zero",
|
||||
"900093": "Zero",
|
||||
"920093": "Zero",
|
||||
"9000c1": "Zero W",
|
||||
"a02082": "3B",
|
||||
"a020a0": "CM3",
|
||||
"a22082": "3B",
|
||||
"a32082": "3B",
|
||||
}
|
||||
|
||||
|
||||
def get_octopi_version():
|
||||
with open(_OCTOPI_VERSION_PATH, "r") as f:
|
||||
version_line = f.readline()
|
||||
return version_line.strip()
|
||||
|
||||
|
||||
def get_pi_revision():
|
||||
with open(_CPUINFO_PATH) as f:
|
||||
for line in f:
|
||||
if line and line.startswith("Revision:"):
|
||||
return line[line.index(":") + 1:].strip()
|
||||
return "unknown"
|
||||
|
||||
|
||||
def get_pi_model(revision):
|
||||
if revision.startswith("1000"):
|
||||
# strip flag for over-volted (https://elinux.org/RPi_HardwareHistory#Which_Pi_have_I_got.3F)
|
||||
revision = revision[4:]
|
||||
return _RPI_REVISION_MAP.get(revision.lower(), "unknown")
|
||||
|
||||
|
||||
class OctoPiSupportPlugin(octoprint.plugin.EnvironmentDetectionPlugin,
|
||||
octoprint.plugin.SimpleApiPlugin,
|
||||
octoprint.plugin.AssetPlugin,
|
||||
octoprint.plugin.TemplatePlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._version = None
|
||||
self._revision = None
|
||||
self._model = None
|
||||
|
||||
#~~ EnvironmentDetectionPlugin
|
||||
|
||||
def get_additional_environment(self):
|
||||
return dict(version=self._get_version(),
|
||||
revision=self._get_revision(),
|
||||
model=self._get_model())
|
||||
|
||||
#~~ SimpleApiPlugin
|
||||
|
||||
def on_api_get(self, request):
|
||||
return flask.jsonify(version=self._get_version(),
|
||||
revision=self._get_revision(),
|
||||
model=self._get_model())
|
||||
|
||||
#~~ AssetPlugin
|
||||
|
||||
def get_assets(self):
|
||||
return dict(
|
||||
js=["js/octopi_support.js"],
|
||||
css=["css/octopi_support.css"]
|
||||
)
|
||||
|
||||
#~~ TemplatePlugin
|
||||
|
||||
def get_template_configs(self):
|
||||
return [
|
||||
dict(type="about", name="About OctoPi", template="octopi_support_about.jinja2")
|
||||
]
|
||||
|
||||
def get_template_vars(self):
|
||||
version = self._get_version()
|
||||
revision = self._get_revision()
|
||||
model = self._get_model()
|
||||
|
||||
return dict(version=version,
|
||||
rpi=(revision is not None and revision != "unknown" and model is not None and model != "unknown"),
|
||||
rpi_revision=revision,
|
||||
rpi_model=model)
|
||||
|
||||
#~~ Helpers
|
||||
|
||||
def _get_version(self):
|
||||
if self._version is None:
|
||||
try:
|
||||
self._version = get_octopi_version()
|
||||
except:
|
||||
self._logger.exception("Error while reading OctoPi version from file {}".format(_OCTOPI_VERSION_PATH))
|
||||
return self._version
|
||||
|
||||
def _get_model(self):
|
||||
if self._model is None:
|
||||
try:
|
||||
self._model = get_pi_model(self._get_revision())
|
||||
except:
|
||||
self._logger.exception("Error while detecting RPi model")
|
||||
return self._model
|
||||
|
||||
def _get_revision(self):
|
||||
if self._revision is None:
|
||||
try:
|
||||
self._revision = get_pi_revision()
|
||||
except:
|
||||
self._logger.exception("Error while detecting RPi revision")
|
||||
return self._revision
|
||||
|
||||
def __plugin_check__():
|
||||
from octoprint.util.platform import get_os
|
||||
return get_os() == "linux" and os.path.exists(_OCTOPI_VERSION_PATH)
|
||||
|
||||
def __plugin_load__():
|
||||
global __plugin_implementation__
|
||||
__plugin_implementation__ = OctoPiSupportPlugin()
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#octopi_support_footer {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrintClient"], factory);
|
||||
} else {
|
||||
factory(global.OctoPrintClient);
|
||||
}
|
||||
})(this, function(OctoPrintClient) {
|
||||
var OctoPrintOctoPiSupportClient = function(base) {
|
||||
this.base = base;
|
||||
};
|
||||
|
||||
OctoPrintOctoPiSupportClient.prototype.get = function(opts) {
|
||||
return this.base.get(this.base.getSimpleApiUrl("octopi_support"));
|
||||
};
|
||||
|
||||
OctoPrintClient.registerPluginComponent("octopi_support", OctoPrintOctoPiSupportClient);
|
||||
return OctoPrintOctoPiSupportClient;
|
||||
});
|
||||
|
||||
$(function() {
|
||||
|
||||
function OctoPiSupportViewModel(parameters) {
|
||||
var self = this;
|
||||
|
||||
self.requestData = function() {
|
||||
OctoPrint.plugins.octopi_support.get()
|
||||
.done(function(response) {
|
||||
$("#octopi_support_footer").remove();
|
||||
if (!response.version) return;
|
||||
|
||||
var octoPrintVersion = $(".footer span.version");
|
||||
var octoPiVersion = $("<span id='octopi_support_footer'> " + gettext("running on") + " " + gettext("OctoPi")
|
||||
+ " <span class='octopi_version'>" + response.version + "</span></span>")
|
||||
$(octoPiVersion).insertAfter(octoPrintVersion);
|
||||
})
|
||||
};
|
||||
|
||||
self.onStartup = function() {
|
||||
self.requestData();
|
||||
};
|
||||
|
||||
self.onServerReconnect = function() {
|
||||
self.requestData();
|
||||
};
|
||||
}
|
||||
|
||||
// view model class, parameters for constructor, container to bind to
|
||||
ADDITIONAL_VIEWMODELS.push([
|
||||
OctoPiSupportViewModel,
|
||||
[],
|
||||
[]
|
||||
]);
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<h3>{{ _('About OctoPi') }}</h3>
|
||||
|
||||
<h4>{{ _('The ready-to-go Raspberry Pi image with OctoPrint') }}</h4>
|
||||
|
||||
<p>Version <span class="plugin_octopi_support_version">{{ plugin_octopi_support_version }}</span></p>
|
||||
|
||||
<ul>
|
||||
<li>Website: <a href="http://octoprint.org/download/" target="_blank" rel="noreferrer noopener">octoprint.org/download</a> & <a href="https://octopi.octoprint.org" target="_blank" rel="noreferrer noopener">octopi.octoprint.org</a></li>
|
||||
<li>Source Code: <a href="https://github.com/guysoft/OctoPi" target="_blank" rel="noreferrer noopener">github.com/guysoft/OctoPi</a></li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
© 2013-{{ now.strftime("%Y") }} <a href="https://github.com/guysoft/OctoPi/graphs/contributors" target="_blank" rel="noreferrer noopener">The OctoPi Authors</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
OctoPi is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
</p>
|
||||
<p>
|
||||
OctoPi is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
</p>
|
||||
<p>
|
||||
For a copy of the GNU General Public License, see
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank" rel="noreferrer noopener">www.gnu.org/licenses/gpl-3.0.en.html</a>.
|
||||
</p>
|
||||
|
||||
{% if plugin_octopi_support_rpi %}
|
||||
<h3>{{ _('About this Raspberry Pi') }}</h3>
|
||||
|
||||
<ul>
|
||||
<li>Model: {{ plugin_octopi_support_rpi_model }}</li>
|
||||
<li>Revision: {{ plugin_octopi_support_rpi_revision }}</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
|
|
@ -15,6 +15,7 @@ from octoprint.server.util.flask import restricted_access, with_revalidation_che
|
|||
from octoprint.server import admin_permission, VERSION
|
||||
from octoprint.util.pip import LocalPipCaller, UnknownPip
|
||||
from octoprint.util.version import get_octoprint_version_string, get_octoprint_version, is_octoprint_compatible
|
||||
from octoprint.util.platform import get_os
|
||||
|
||||
from flask import jsonify, make_response
|
||||
from flask.ext.babel import gettext
|
||||
|
|
@ -241,7 +242,7 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
available=self._repository_available,
|
||||
plugins=self._repository_plugins
|
||||
),
|
||||
os=self._get_os(),
|
||||
os=get_os(),
|
||||
octoprint=get_octoprint_version_string(),
|
||||
pip=dict(
|
||||
available=self._pip_caller.available,
|
||||
|
|
@ -759,7 +760,7 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
if repo_data is None:
|
||||
return False
|
||||
|
||||
current_os = self._get_os()
|
||||
current_os = get_os()
|
||||
octoprint_version = get_octoprint_version(base=True)
|
||||
|
||||
def map_repository_entry(entry):
|
||||
|
|
@ -878,14 +879,6 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
|
||||
return positive_match and not negative_match
|
||||
|
||||
@classmethod
|
||||
def _get_os(cls):
|
||||
for identifier, platforms in cls.OPERATING_SYSTEMS.items():
|
||||
if (callable(platforms) and platforms(sys.platform)) or (isinstance(platforms, list) and sys.platform in platforms):
|
||||
return identifier
|
||||
else:
|
||||
return "unmapped"
|
||||
|
||||
@property
|
||||
def _reconnect_hooks(self):
|
||||
reconnect_hooks = self.__class__.RECONNECT_HOOKS
|
||||
|
|
|
|||
|
|
@ -146,11 +146,13 @@ def load_user(id):
|
|||
|
||||
|
||||
class Server(object):
|
||||
def __init__(self, settings=None, plugin_manager=None, connectivity_checker=None, event_manager=None,
|
||||
host="0.0.0.0", port=5000, debug=False, safe_mode=False, allow_root=False, octoprint_daemon=None):
|
||||
def __init__(self, settings=None, plugin_manager=None, connectivity_checker=None, environment_detector=None,
|
||||
event_manager=None, host="0.0.0.0", port=5000, debug=False, safe_mode=False, allow_root=False,
|
||||
octoprint_daemon=None):
|
||||
self._settings = settings
|
||||
self._plugin_manager = plugin_manager
|
||||
self._connectivity_checker = connectivity_checker
|
||||
self._environment_detector = environment_detector
|
||||
self._event_manager = event_manager
|
||||
self._host = host
|
||||
self._port = port
|
||||
|
|
@ -290,7 +292,8 @@ class Server(object):
|
|||
app_session_manager=appSessionManager,
|
||||
plugin_lifecycle_manager=pluginLifecycleManager,
|
||||
preemptive_cache=preemptiveCache,
|
||||
connectivity_checker=connectivityChecker
|
||||
connectivity_checker=connectivityChecker,
|
||||
environment_detector=self._environment_detector
|
||||
)
|
||||
|
||||
# create user manager instance
|
||||
|
|
@ -390,6 +393,9 @@ class Server(object):
|
|||
pluginManager.implementation_post_inits=[settings_plugin_config_migration_and_cleanup]
|
||||
|
||||
pluginManager.log_all_plugins()
|
||||
|
||||
# log environment data now
|
||||
self._environment_detector.log_detected_environment()
|
||||
|
||||
# initialize file manager and register it for changes in the registered plugins
|
||||
fileManager.initialize()
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ default_settings = {
|
|||
],
|
||||
"usersettings": ["access", "interface"],
|
||||
"wizard": ["access"],
|
||||
"about": ["about", "supporters", "authors", "changelog", "license", "thirdparty", "plugin_pluginmanager"],
|
||||
"about": ["about", "plugin_octopi_support", "supporters", "authors", "changelog", "license", "thirdparty", "plugin_pluginmanager"],
|
||||
"generic": []
|
||||
},
|
||||
"disabled": {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -942,6 +942,11 @@ ul.dropdown-menu li a {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#footer_version,
|
||||
#footer_link {
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
/** Notifications */
|
||||
|
|
|
|||
|
|
@ -110,14 +110,14 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<ul class="pull-left muted">
|
||||
<ul id="footer_version" class="pull-left muted">
|
||||
<li><small>{{ _('OctoPrint') }} <span class="version">{{ display_version|e }}</span></small></li>
|
||||
</ul>
|
||||
<ul class="pull-right">
|
||||
<ul id="footer_links" class="pull-right">
|
||||
<li><a href="http://octoprint.org" target="_blank" rel="noreferrer noopener"><i class="fa fa-home"></i> {{ _('Homepage') }}</a></li>
|
||||
<li><a href="https://github.com/foosel/OctoPrint/" target="_blank" rel="noreferrer noopener"><i class="fa fa-github"></i> {{ _('Sourcecode') }}</a></li>
|
||||
<li><a href="http://docs.octoprint.org" target="_blank" rel="noreferrer noopener"><i class="fa fa-book"></i> {{ _('Documentation') }}</a></li>
|
||||
<li><a href="https://github.com/foosel/OctoPrint/issues" target="_blank" rel="noreferrer noopener"><i class="fa fa-flag"></i> {{ _('Bugs and Requests') }}</a></li>
|
||||
<li><a href="https://github.com/foosel/OctoPrint/" target="_blank" rel="noreferrer noopener"><i class="fa fa-github"></i> {{ _('Source') }}</a></li>
|
||||
<li><a href="http://docs.octoprint.org" target="_blank" rel="noreferrer noopener"><i class="fa fa-book"></i> {{ _('Docs') }}</a></li>
|
||||
<li><a href="https://github.com/foosel/OctoPrint/issues" target="_blank" rel="noreferrer noopener"><i class="fa fa-flag"></i> {{ _('Issues') }}</a></li>
|
||||
<li><a href="https://github.com/foosel/OctoPrint/wiki/FAQ" target="_blank" rel="noreferrer noopener"><i class="fa fa-question-circle"></i> {{ _('FAQ') }}</a></li>
|
||||
<li id="footer_about"><a href="javascript:void(0)" data-bind="click: show"><i class="fa fa-info-circle"></i> {{ _('About') }}</a></li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -39,3 +39,19 @@ else:
|
|||
def set_close_exec(handle):
|
||||
# no-op
|
||||
pass
|
||||
|
||||
|
||||
# current os
|
||||
|
||||
_OPERATING_SYSTEMS = dict(windows=["win32"],
|
||||
linux=lambda x: x.startswith("linux"),
|
||||
macos=["darwin"],
|
||||
freebsd=lambda x: x.startswith("freebsd"))
|
||||
OPERATING_SYSTEM_UNMAPPED = "unmapped"
|
||||
|
||||
def get_os():
|
||||
for identifier, platforms in _OPERATING_SYSTEMS.items():
|
||||
if (callable(platforms) and platforms(sys.platform)) or (isinstance(platforms, list) and sys.platform in platforms):
|
||||
return identifier
|
||||
else:
|
||||
return OPERATING_SYSTEM_UNMAPPED
|
||||
|
|
|
|||
|
|
@ -42,20 +42,3 @@ class PluginManagerPluginTests(unittest.TestCase):
|
|||
with mock.patch("sys.platform", sys_platform):
|
||||
actual = PluginManagerPlugin._is_os_compatible(current_os, entries)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@ddt.data(
|
||||
("win32", "windows"),
|
||||
("linux2", "linux"),
|
||||
("darwin", "macos"),
|
||||
("linux", "linux"),
|
||||
("linux3", "linux"),
|
||||
("freebsd", "freebsd"),
|
||||
("freebsd2342", "freebsd"),
|
||||
("os2", "unmapped"),
|
||||
("sunos5", "unmapped")
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_get_os(self, sys_platform, expected):
|
||||
with mock.patch("sys.platform", sys_platform):
|
||||
actual = PluginManagerPlugin._get_os()
|
||||
self.assertEqual(actual, expected)
|
||||
|
|
|
|||
30
tests/util/test_platform.py
Normal file
30
tests/util/test_platform.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# coding=utf-8
|
||||
from __future__ import absolute_import
|
||||
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
__copyright__ = "Copyright (C) 2017 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
||||
|
||||
import unittest
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
@ddt.ddt
|
||||
class PlatformUtilTest(unittest.TestCase):
|
||||
|
||||
@ddt.data(
|
||||
("win32", "windows"),
|
||||
("linux2", "linux"),
|
||||
("darwin", "macos"),
|
||||
("linux", "linux"),
|
||||
("linux3", "linux"),
|
||||
("freebsd", "freebsd"),
|
||||
("freebsd2342", "freebsd"),
|
||||
("os2", "unmapped"),
|
||||
("sunos5", "unmapped")
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_get_os(self, sys_platform, expected):
|
||||
with mock.patch("sys.platform", sys_platform):
|
||||
from octoprint.util.platform import get_os
|
||||
actual = get_os()
|
||||
self.assertEqual(actual, expected)
|
||||
Loading…
Reference in a new issue