Permalink
Comparing changes
Open a pull request
2
contributors
Commits on Jul 02, 2015
When using the version cache only use the version cache if the OctoPrint version stored within it matches the one of the currently running instance. Otherwise we might report false positives with regards to available updates under some circumstances. (cherry picked from commit bb7b0cb)
Commits on Jul 05, 2015
Commits on Jul 06, 2015
Commits on Jul 07, 2015
Commits on Jul 08, 2015
Two changes:
* Asset existence will now be checked before they get included
in the assets to bundle by webassets, logging a warning if a
file isn't present.
* Monkey-patched webassets filter chain to not die when a file
doesn't exist, but to log an error instead and just return
an empty file instead.
(cherry picked from commit 2a5ec33)
- Convert query term to lower case so that it is case insensitive both ways
- Knockout submit binding takes the form element as parameter and return
value determines whether the form submit occurs. See http://knockoutjs.com/documentation/submit-binding.html
(cherry picked from commit 4a2cc53)
Unified
Split
Showing
with
1,055 additions
and 1,350 deletions.
- +3 −3 .versioneer-lookup
- +32 −0 CHANGELOG.md
- +69 −0 docs/features/accesscontrol.rst
- +14 −2 docs/features/custom_controls.rst
- +1 −0 docs/features/index.rst
- +1 −1 docs/features/plugins.rst
- +4 −0 docs/index.rst
- +9 −3 src/octoprint/plugin/types.py
- +31 −23 src/octoprint/plugins/cura/__init__.py
- +3 −3 src/octoprint/plugins/pluginmanager/__init__.py
- +3 −5 src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js
- +51 −10 src/octoprint/plugins/softwareupdate/__init__.py
- +1 −1 src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js
- +5 −5 src/octoprint/plugins/softwareupdate/updaters/pip.py
- +59 −18 src/octoprint/plugins/softwareupdate/version_checks/github_release.py
- +13 −3 src/octoprint/server/__init__.py
- +3 −1 src/octoprint/server/api/settings.py
- +44 −0 src/octoprint/server/util/flask.py
- +5 −0 src/octoprint/server/util/watchdog.py
- +2 −1 src/octoprint/settings.py
- +5 −6 src/octoprint/static/js/app/viewmodels/files.js
- +4 −1 src/octoprint/static/js/app/viewmodels/settings.js
- +7 −0 src/octoprint/templates/dialogs/settings/folders.jinja2
- +1 −1 src/octoprint/templates/dialogs/settings/serialconnection.jinja2
- BIN src/octoprint/translations/de/LC_MESSAGES/messages.mo
- +270 −576 src/octoprint/translations/de/LC_MESSAGES/messages.po
- +18 −4 src/octoprint/util/__init__.py
- +13 −7 src/octoprint/util/comm.py
- +5 −0 src/octoprint/util/pip.py
- BIN translations/de/LC_MESSAGES/messages.mo
- +270 −576 translations/de/LC_MESSAGES/messages.po
- +109 −100 translations/messages.pot
| @@ -10,10 +10,10 @@ | ||
| # master shall not use the lookup table, only tags | ||
| master | ||
|
|
||
| # maintenance is currently the branch for preparation of maintenance release 1.2.2 | ||
| # maintenance is currently the branch for preparation of maintenance release 1.2.3 | ||
| # so are any fix/... branches | ||
| maintenance 1.2.2-dev 9f8d30a66c2fcc5cd0e8984c72dc36f7e84fde10 | ||
| fix/.* 1.2.2-dev 9f8d30a66c2fcc5cd0e8984c72dc36f7e84fde10 | ||
| maintenance 1.2.3-dev 1c6b0554c796f03ed539397daa4b13c44d05a99d | ||
| fix/.* 1.2.3-dev 1c6b0554c796f03ed539397daa4b13c44d05a99d | ||
|
|
||
| # every other branch is a development branch and thus gets resolved to 1.3.0-dev for now | ||
| .* 1.3.0-dev 198d3450d94be1a2 | ||
| @@ -1,5 +1,37 @@ | ||
| # OctoPrint Changelog | ||
|
|
||
| ## 1.2.3 (2015-07-09) | ||
|
|
||
| ### Improvements | ||
|
|
||
| * New option to actively poll the watched folder. This should make it work also | ||
| if it is mounted on a filesystem that doesn't allow getting notifications | ||
| about added files through notification by the operating system (e.g. | ||
| network shares). | ||
| * Better resilience against senseless temperature/SD-status-polling intervals | ||
| (such as 0). | ||
| * Log exceptions during writing to the serial port to `octoprint.log`. | ||
|
|
||
| ### Bug Fixes | ||
|
|
||
| * [#961](https://github.com/foosel/OctoPrint/pull/961) - Fixed a JavaScript error that caused an error to be logged when "enter" was pressed in file or plugin search. | ||
| * [#962](https://github.com/foosel/OctoPrint/pull/962) - ``url(...)``s in packed CSS and LESS files should now be rewritten properly too to refer to correct paths | ||
| * Update notifications were not vanishing properly after updating: | ||
| * Only use version cache for update notifications if the OctoPrint version still is the same to make sure the cache gets invalidated after an external update of OctoPrint. | ||
| * Do not persist version information when saving settings of the Software Update plugin | ||
| * Always delete files from the ``watched`` folder after importing then. Using file preprocessor plugins could lead to the files staying there. | ||
| * Fixed an encoding problem causing OctoPrint's Plugin Manager and Software Update plugins to choke on UTF-8 characters in the update output. | ||
| * Fixed sorting by file size in file list | ||
| * More resilience against missing plugin assets: | ||
| * Asset existence will now be checked before they get included | ||
| in the assets to bundle by webassets, logging a warning if a | ||
| file isn't present. | ||
| * Monkey-patched webassets filter chain to not die when a file | ||
| doesn't exist, but to log an error instead and just return | ||
| an empty file instead. | ||
|
|
||
| ([Commits](https://github.com/foosel/OctoPrint/compare/1.2.2...1.2.3)) | ||
|
|
||
| ## 1.2.2 (2015-06-30) | ||
|
|
||
| ### Bug Fixes | ||
| @@ -0,0 +1,69 @@ | ||
| .. _sec-features-access_control: | ||
|
|
||
| Access Control | ||
| ============== | ||
|
|
||
| When Access Control is enabled, anonymous users (not logged in) will only see | ||
| the read-only parts of the UI which are the following: | ||
|
|
||
| * printer state | ||
| * available gcode files and stats (upload is disabled) | ||
| * temperature | ||
| * webcam | ||
| * gcode viewer | ||
| * terminal output (sending commands is disabled) | ||
| * available timelapse movies | ||
| * any components provided through plugins which are enabled for anonymous | ||
| users | ||
|
|
||
| Logged in users will get access to everything besides the Settings and System | ||
| Commands, which are admin-only. | ||
|
|
||
| If Access Control is disabled, everything is directly accessible. **That also | ||
| includes all administrative functionality as well as full control over the | ||
| printer!** | ||
|
|
||
| Upon first start a configuration wizard is provided which allows configuration | ||
| of the first administrator account or alternatively disabling Access Control | ||
| (which is **NOT** recommended for systems that are directly accessible via the | ||
| Internet!). | ||
|
|
||
| .. hint:: | ||
|
|
||
| If you plan to have your OctoPrint instance accessible over the internet, | ||
| **always enable Access Control**. | ||
|
|
||
| .. _sec-features-access_control-rerunning_wizard: | ||
|
|
||
| Rerunning the wizard | ||
| -------------------- | ||
|
|
||
| In case Access Control was disabled in the configuration wizard, it is | ||
| possibly to re-run it by editing ``config.yaml`` [#f1]_ and setting ``firstRun`` | ||
| in the ``server`` section and ``enabled`` in the ``accessControl`` section to | ||
| ``true``: | ||
|
|
||
| .. code-block-ext:: yaml | ||
|
|
||
| accessControl: | ||
| enabled: true | ||
| # ... | ||
| server: | ||
| firstRun: true | ||
|
|
||
| Then restart the server and connect to the web interface - the wizard should | ||
| be shown again. | ||
|
|
||
| .. note:: | ||
|
|
||
| If user accounts were created prior to disabling Access Control and those | ||
| user accounts are not to be used any more, remove ``.octoprint/users.yaml``. | ||
| If you don't remove this file, the above changes won't lead to the | ||
| configuration being shown again, instead Access Control will just be | ||
| enabled using the already existing login data. This is to prevent you from | ||
| resetting access control by accident. | ||
|
|
||
| .. rubric:: Footnotes | ||
|
|
||
| .. [#f1] For Linux that will be ``~/.octoprint/config.yaml``, for Windows it will be ``%APPDATA%/OctoPrint/config.yaml`` and for | ||
| Mac ``~/Library/Application Support/OctoPrint/config.yaml`` |
| @@ -10,7 +10,7 @@ buttons which trigger sending of one or more lines of GCODE to the printer over | ||
| parameterization of these commands with values entered by the user to full blown GCODE script templates backed by | ||
| `Jinja2 <http://jinja.pocoo.org/>`_. | ||
|
|
||
| Custom controls are configured within :ref:`config.yaml <sec-configuration-config_yaml>` in a ``controls`` section which | ||
| Custom controls are configured within :ref:`config.yaml <sec-configuration-config_yaml>` [#f1]_ in a ``controls`` section which | ||
| basically represents a hierarchical structure of all configured custom controls of various types. | ||
|
|
||
| .. note:: | ||
| @@ -94,6 +94,13 @@ button that sends one or more commands to the printer when clicked, displaying o | ||
| controls that just serve as *container* for other controls, the latter being identified by having a ``children`` | ||
| attribute wrapping more controls. | ||
|
|
||
| .. hint:: | ||
|
|
||
| Take a look at the `Custom Control Editor plugin <http://plugins.octoprint.org/plugins/customControl/>`_ | ||
| which allows you configuring your Custom Controls through OctoPrint's | ||
| settings interface without the need to manually edit the configuration | ||
| file. | ||
|
|
||
| .. _sec-features-custom_controls-types: | ||
|
|
||
| Types | ||
| @@ -278,4 +285,9 @@ Parameterized GCODE Script | ||
| G28 X0 Y0 | ||
|
|
||
| Note the usage of the ``parameters.repetitions`` template variable in the GCODE script template, which will contain | ||
| the value selected by the user for the "Go arounds" slider. | ||
| the value selected by the user for the "Go arounds" slider. | ||
|
|
||
| .. rubric:: Footnotes | ||
|
|
||
| .. [#f1] For Linux that will be ``~/.octoprint/config.yaml``, for Windows it will be ``%APPDATA%/OctoPrint/config.yaml`` and for | ||
| Mac ``~/Library/Application Support/OctoPrint/config.yaml`` | ||
| @@ -7,6 +7,7 @@ Features | ||
| .. toctree:: | ||
| :maxdepth: 2 | ||
|
|
||
| accesscontrol.rst | ||
| custom_controls.rst | ||
| gcode_scripts.rst | ||
| action_commands.rst | ||
| @@ -64,7 +64,7 @@ See :ref:`Developing Plugins <sec-plugins>`. | ||
| .. rubric:: Footnotes | ||
|
|
||
| .. [#f1] For Linux that will be ``~/.octoprint/plugins``, for Windows it will be ``%APPDATA%/OctoPrint/plugins`` and for | ||
| Mac ``~/Library/Application Support/OctoPrint`` | ||
| Mac ``~/Library/Application Support/OctoPrint/plugins`` | ||
| .. [#f2] Make sure to use the exact same Python installation for installing the plugin that you also used for | ||
| installing & running OctoPrint. For OctoPi this means using ``~/oprint/bin/pip`` for installing plugins | ||
| instead of just ``pip``. | ||
| @@ -6,6 +6,10 @@ Welcome to OctoPrint's documentation! | ||
| :alt: The OctoPrint Logo | ||
| :align: right | ||
|
|
||
| This documentation is still in the process of being migrated from | ||
| `OctoPrint's wiki <https://github.com/foosel/OctoPrint/wiki>`_, so also take | ||
| a look there! | ||
|
|
||
| Contents | ||
| ======== | ||
|
|
||
| @@ -781,7 +781,10 @@ def on_settings_load(self): | ||
| :return: the current settings of the plugin, as a dictionary | ||
| """ | ||
| return self._settings.get([], asdict=True, merged=True) | ||
| data = self._settings.get([], asdict=True, merged=True) | ||
| if "_config_version" in data: | ||
| del data["_config_version"] | ||
| return data | ||
|
|
||
| def on_settings_save(self, data): | ||
| """ | ||
| @@ -803,9 +806,12 @@ def on_settings_save(self, data): | ||
| """ | ||
| import octoprint.util | ||
|
|
||
| if "_config_version" in data: | ||
| del data["_config_version"] | ||
|
|
||
| current = self._settings.get([], asdict=True, merged=True) | ||
| data = octoprint.util.dict_merge(current, data) | ||
| self._settings.set([], data) | ||
| merged = octoprint.util.dict_merge(current, data) | ||
| self._settings.set([], merged) | ||
|
|
||
| def get_settings_defaults(self): | ||
| """ | ||
| @@ -35,6 +35,14 @@ def __init__(self): | ||
| self._cancelled_jobs = [] | ||
| self._job_mutex = threading.Lock() | ||
|
|
||
| ##~~ TemplatePlugin API | ||
|
|
||
| def get_template_configs(self): | ||
| from flask.ext.babel import gettext | ||
| return [ | ||
| dict(type="settings", name=gettext("CuraEngine")) | ||
| ] | ||
|
|
||
| ##~~ StartupPlugin API | ||
|
|
||
| def on_startup(self, host, port): | ||
| @@ -218,7 +226,7 @@ def do_slice(self, model_path, printer_profile, machinecode_path=None, profile_p | ||
| if not on_progress_kwargs: | ||
| on_progress_kwargs = dict() | ||
|
|
||
| self._cura_logger.info("### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path)) | ||
| self._cura_logger.info(u"### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path)) | ||
|
|
||
| engine_settings = self._convert_to_engine(profile_path, printer_profile, posX, posY) | ||
|
|
||
| @@ -227,16 +235,15 @@ def do_slice(self, model_path, printer_profile, machinecode_path=None, profile_p | ||
| return False, "Path to CuraEngine is not configured " | ||
|
|
||
| working_dir, _ = os.path.split(executable) | ||
| args = ['"%s"' % executable, '-v', '-p'] | ||
| args = [executable, '-v', '-p'] | ||
| for k, v in engine_settings.items(): | ||
| args += ["-s", '"%s=%s"' % (k, str(v))] | ||
| args += ['-o', '"%s"' % machinecode_path, '"%s"' % model_path] | ||
| args += ["-s", "%s=%s" % (k, str(v))] | ||
| args += ["-o", machinecode_path, model_path] | ||
|
|
||
| import sarge | ||
| command = " ".join(args) | ||
| self._logger.info("Running %r in %s" % (command, working_dir)) | ||
| self._logger.info(u"Running %r in %s" % (" ".join(args), working_dir)) | ||
|
|
||
| p = sarge.run(command, cwd=working_dir, async=True, stdout=sarge.Capture(), stderr=sarge.Capture()) | ||
| import sarge | ||
| p = sarge.run(args, cwd=working_dir, async=True, stdout=sarge.Capture(), stderr=sarge.Capture()) | ||
| p.wait_events() | ||
| self._slicing_commands[machinecode_path] = p.commands[0] | ||
|
|
||
| @@ -254,6 +261,7 @@ def do_slice(self, model_path, printer_profile, machinecode_path=None, profile_p | ||
| p.commands[0].poll() | ||
| continue | ||
|
|
||
| line = octoprint.util.to_unicode(line, errors="replace") | ||
| self._cura_logger.debug(line.strip()) | ||
|
|
||
| if on_progress is not None: | ||
| @@ -282,14 +290,14 @@ def do_slice(self, model_path, printer_profile, machinecode_path=None, profile_p | ||
| # | ||
| # with <step_factor> being 0 for "inset", 1 for "skin" and 2 for "export". | ||
|
|
||
| if line.startswith("Layer count:") and layer_count is None: | ||
| if line.startswith(u"Layer count:") and layer_count is None: | ||
| try: | ||
| layer_count = float(line[len("Layer count:"):].strip()) | ||
| layer_count = float(line[len(u"Layer count:"):].strip()) | ||
| except: | ||
| pass | ||
|
|
||
| elif line.startswith("Progress:"): | ||
| split_line = line[len("Progress:"):].strip().split(":") | ||
| elif line.startswith(u"Progress:"): | ||
| split_line = line[len(u"Progress:"):].strip().split(":") | ||
| if len(split_line) == 3: | ||
| step, current_layer, _ = split_line | ||
| try: | ||
| @@ -302,21 +310,21 @@ def do_slice(self, model_path, printer_profile, machinecode_path=None, profile_p | ||
| on_progress_kwargs["_progress"] = (step_factor[step] * layer_count + current_layer) / (layer_count * 3) | ||
| on_progress(*on_progress_args, **on_progress_kwargs) | ||
|
|
||
| elif line.startswith("Print time:"): | ||
| elif line.startswith(u"Print time:"): | ||
| try: | ||
| print_time = int(line[len("Print time:"):].strip()) | ||
| print_time = int(line[len(u"Print time:"):].strip()) | ||
| if analysis is None: | ||
| analysis = dict() | ||
| analysis["estimatedPrintTime"] = print_time | ||
| except: | ||
| pass | ||
|
|
||
| elif line.startswith("Filament:") or line.startswith("Filament2:"): | ||
| if line.startswith("Filament:"): | ||
| filament_str = line[len("Filament:"):].strip() | ||
| elif line.startswith(u"Filament:") or line.startswith(u"Filament2:"): | ||
| if line.startswith(u"Filament:"): | ||
| filament_str = line[len(u"Filament:"):].strip() | ||
| tool_key = "tool0" | ||
| else: | ||
| filament_str = line[len("Filament2:"):].strip() | ||
| filament_str = line[len(u"Filament2:"):].strip() | ||
| tool_key = "tool1" | ||
|
|
||
| try: | ||
| @@ -339,20 +347,20 @@ def do_slice(self, model_path, printer_profile, machinecode_path=None, profile_p | ||
|
|
||
| with self._job_mutex: | ||
| if machinecode_path in self._cancelled_jobs: | ||
| self._cura_logger.info("### Cancelled") | ||
| self._cura_logger.info(u"### Cancelled") | ||
| raise octoprint.slicing.SlicingCancelled() | ||
|
|
||
| self._cura_logger.info("### Finished, returncode %d" % p.returncode) | ||
| self._cura_logger.info(u"### Finished, returncode %d" % p.returncode) | ||
| if p.returncode == 0: | ||
| return True, dict(analysis=analysis) | ||
| else: | ||
| self._logger.warn("Could not slice via Cura, got return code %r" % p.returncode) | ||
| self._logger.warn(u"Could not slice via Cura, got return code %r" % p.returncode) | ||
| return False, "Got returncode %r" % p.returncode | ||
|
|
||
| except octoprint.slicing.SlicingCancelled as e: | ||
| raise e | ||
| except: | ||
| self._logger.exception("Could not slice via Cura, got an unknown error") | ||
| self._logger.exception(u"Could not slice via Cura, got an unknown error") | ||
| return False, "Unknown error, please consult the log file" | ||
|
|
||
| finally: | ||
| @@ -371,7 +379,7 @@ def cancel_slicing(self, machinecode_path): | ||
| command = self._slicing_commands[machinecode_path] | ||
| if command is not None: | ||
| command.terminate() | ||
| self._logger.info("Cancelled slicing of %s" % machinecode_path) | ||
| self._logger.info(u"Cancelled slicing of %s" % machinecode_path) | ||
|
|
||
| def _load_profile(self, path): | ||
| import yaml | ||
| @@ -418,13 +418,13 @@ def _call_pip(self, args): | ||
| return self._pip_caller.execute(*args) | ||
|
|
||
| def _log_call(self, *lines): | ||
| self._log(lines, prefix=" ", stream="call") | ||
| self._log(lines, prefix=u" ", stream="call") | ||
|
|
||
| def _log_stdout(self, *lines): | ||
| self._log(lines, prefix=">", stream="stdout") | ||
| self._log(lines, prefix=u">", stream="stdout") | ||
|
|
||
| def _log_stderr(self, *lines): | ||
| self._log(lines, prefix="!", stream="stderr") | ||
| self._log(lines, prefix=u"!", stream="stderr") | ||
|
|
||
| def _log(self, lines, prefix=None, stream=None, strip=True): | ||
| if strip: | ||
| @@ -147,19 +147,17 @@ $(function() { | ||
| } | ||
| }); | ||
|
|
||
| self.performRepositorySearch = function(e) { | ||
| if (e !== undefined) { | ||
| e.preventDefault(); | ||
| } | ||
|
|
||
| self.performRepositorySearch = function() { | ||
| var query = self.repositorySearchQuery(); | ||
| if (query !== undefined && query.trim() != "") { | ||
| query = query.toLocaleLowerCase(); | ||
| self.repositoryplugins.changeSearchFunction(function(entry) { | ||
| return entry && (entry["title"].toLocaleLowerCase().indexOf(query) > -1 || entry["description"].toLocaleLowerCase().indexOf(query) > -1); | ||
| }); | ||
| } else { | ||
| self.repositoryplugins.resetSearch(); | ||
| } | ||
| return false; | ||
| }; | ||
|
|
||
| self.fromResponse = function(data) { | ||
Oops, something went wrong.