From 354042b84d488db38ac1917bb69bd164f4e7f750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Fri, 23 Sep 2016 09:51:45 +0200 Subject: [PATCH 1/5] Preparing release of 1.2.16 --- .github/ISSUE_TEMPLATE.md | 30 ++++++++++++++++++++---------- CHANGELOG.md | 25 ++++++++++--------------- CONTRIBUTING.md | 28 ++++++++++++++++++---------- README.md | 24 ++++++++---------------- 4 files changed, 56 insertions(+), 51 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index bfb6508a..c1e15699 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,21 +1,31 @@ -Please read the "guidelines for contributing" that are linked ^-- just -up there. Also read the FAQ: https://github.com/foosel/OctoPrint/wiki/FAQ. +READ THE FOLLOWING FIRST: + +If not already done, please read the "guidelines for contributing" +that are linked ^-- just up there in the big yellow box. Also read +the FAQ: https://github.com/foosel/OctoPrint/wiki/FAQ. This is a bug and feature tracker, please only use it to report bugs or request features within OctoPrint (not OctoPi, not any OctoPrint -plugins and not unofficial OctoPrint versions). Mark requests with -a [Request] prefix in the title please. Fully fill out the bug reporting -template for bug reports. Do not delete any lines from the template but -those enclosed in [ and ] - and those please do delete, they are only -provided for your information and removing them makes your ticket more -readable :) +plugins and not unofficial OctoPrint versions). Do not seek support here ("I need help with ..."), that belongs on the mailing list or the G+ community (both linked in the "guidelines for contributing" linked above, read it!), NOT here. +Mark requests with a "[Request]" prefix in the title please. Fully fill +out the bug reporting template for bug reports (if you don't know where +to find some information - it's all described in the contribution +guidelines linked up there in the big yellow box). Do not delete any +lines from the template but those enclosed in [ and ] - and those please +DO delete, they are only provided for your information and removing them +makes your ticket more readable :) + Thank you! +(Before submitting your ticket, please delete this text up to and +including the line too - it's only here for you, we already know it +by heart ;)) + ---- #### What were you doing? @@ -53,8 +63,8 @@ to also include a link to a file with which to reproduce the problem.] reporting communication issues. Never truncate. serial.log is usually not written due to performance reasons and must be -enabled explicitly. Provide at the very least the contents of your -terminal tab at the time of the bug occurence, even if you do not have +enabled explicitly. Provide at the very least the FULL contents of your +terminal tab at the time of the bug occurrence, even if you do not have a serial.log.] #### Link to contents of Javascript console in the browser diff --git a/CHANGELOG.md b/CHANGELOG.md index 3039cb41..ce31a452 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,6 @@ # OctoPrint Changelog -## 1.2.16rc2 (2016-09-16) - -### Improvements - - * Return a "400 Bad Request" instead of a "500 Internal Server Error" if a `multipart/form-data` request (e.g. a file upload) is sent which lacks the `boundary` field. - -### Bug Fixes - - * [#1491](https://github.com/foosel/OctoPrint/issues/1491): Fixed generate/delete API key in the user settings - * [#1492](https://github.com/foosel/OctoPrint/issues/1492): Fixed a bug in the software update plugin depending on the presence of the ``prerelease`` flag which is only present when added manually or using a non stable release channel. - -([Commits](https://github.com/foosel/OctoPrint/compare/1.2.16rc1...1.2.16rc2)) - -## 1.2.16rc1 (2016-09-09) +## 1.2.16 (2016-09-23) ### Improvements @@ -23,6 +10,7 @@ * Improved fuzzy print time displays in the frontend. Rounding now takes overall duration into account - durations over a day will be rounded up/down to half days, durations over an hour will be rounded up/down to half hours, durations over 30min will be rounded to 10min segments, durations below 30min will be rounded up or down to the next minute depending on the seconds and finally if we are talking about less than a minute, durations over 30s will return "less than a minute", durations under 30s will return "a couple of seconds". * Improved intermediary loading page: Don't report server as ready and reload until preliminary caching has been done, IF preliminary caching will be done. * Added release channels to OctoPrint's bundled Software Update plugin. You will now be able to subscribe to OctoPrint's `maintenance` or `devel` release candidates in addition to stable versions. [Read more about Release Channels on the wiki](https://github.com/foosel/OctoPrint/wiki/Using-Release-Channels). + * Return a "400 Bad Request" instead of a "500 Internal Server Error" if a `multipart/form-data` request (e.g. a file upload) is sent which lacks the `boundary` field. ### Bug Fixes @@ -31,8 +19,15 @@ * [#1478](https://github.com/foosel/OctoPrint/issues/1478): Don't display inaccurate linear estimate ("6 days remaining") until 30 *minutes* have passed, even if nothing else is available. Potentially related to [#1428](https://github.com/foosel/OctoPrint/issues/1428). * [#1479](https://github.com/foosel/OctoPrint/issues/1479): Make sure set cookies are post fixed with a port specific suffix and that the path they are set on takes the script root from the request into account. * [#1483](https://github.com/foosel/OctoPrint/issues/1483): Filenames in file uploads may also now be encoded in ISO-8859-1, as defined in [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2.4). Solves an issue when sending files with non-ASCII-characters in the file name from Slic3r. + * [#1491](https://github.com/foosel/OctoPrint/issues/1491): Fixed generate/delete API key in the user settings + * [#1492](https://github.com/foosel/OctoPrint/issues/1492): Fixed a bug in the software update plugin depending on the presence of the ``prerelease`` flag which is only present when added manually or using a non stable release channel. -([Commits](https://github.com/foosel/OctoPrint/compare/1.2.15...1.2.16rc1)) +### More information + + * [Commits](https://github.com/foosel/OctoPrint/compare/1.2.15...1.2.16) + * Release Candidates: + * [1.2.16rc1](https://github.com/foosel/OctoPrint/releases/tag/1.2.16rc1) + * [1.2.16rc2](https://github.com/foosel/OctoPrint/releases/tag/1.2.16rc2) ## 1.2.15 (2016-07-30) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6349926..c999c998 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,10 +63,11 @@ available for the maintainers to directly start tackling that problem. ## How to file a bug report If you encounter an issue with OctoPrint, you are welcome to -[submit a bug report](https://goo.gl/GzkGv9). +[submit a bug report](https://github.com/foosel/OctoPrint/issues/new). Before you do that for the first time though please take a moment to read the -following section *completely*. Thank you! :) +following section *completely* and also follow the instructions in the +"new issue" form. Thank you! :) ### What should I do before submitting a bug report? @@ -85,7 +86,7 @@ following section *completely*. Thank you! :) might have installed**. Report any issues with those in their corresponding bug tracker (probably linked to from the plugin's homepage). - Finally, **this is also not the right issue tracker if you are running an + Finally, **this is also not the right issue tracker if you are running a forked version of OctoPrint**. Seek help for such unofficial versions from the people maintaining them instead. @@ -123,7 +124,10 @@ following section *completely*. Thank you! :) ### What should I include in a bug report? -Always use the following template (please remove what's within `[...]`, that's +First of all make sure your use **a descriptive title**. "It doesn't work" +and similar unspecific complaints are NOT descriptive titles. + +**Always use the following template** (please remove what's within `[...]`, that's only provided here as some additional information for you), **even if only adding a "me too" to an existing ticket**: @@ -162,8 +166,8 @@ only provided here as some additional information for you), **even if only addin reporting communication issues. Never truncate. serial.log is usually not written due to performance reasons and must be - enabled explicitly. Provide at the very least the contents of your - terminal tab at the time of the bug occurence, even if you do not have + enabled explicitly. Provide at the very least the FULL contents of your + terminal tab at the time of the bug occurrence, even if you do not have a serial.log.] #### Link to contents of Javascript console in the browser @@ -177,7 +181,8 @@ only provided here as some additional information for you), **even if only addin I have read the FAQ. -Copy-paste this template **completely**. Do not skip any lines! +Copy-paste this template **completely**. Do not skip any lines or the bot +*will* complain! ### Where can I find which version and branch I'm on? @@ -201,15 +206,16 @@ more information is needed. One is contained in the **"Terminal" tab** within OctoPrint's UI and is a log of the last 300 lines of communication with the printer. Please copy-paste -this somewhere (disable auto scroll to make copying the contents easier) - +this *completely* somewhere (disable auto scroll to make copying the contents easier) - e.g. http://pastebin.com or http://gist.github.com - and include a link in your bug report. There is also **OctoPrint's application log file** or in short `octoprint.log`, which is by default located at `~/.octoprint/logs/octoprint.log` on Linux, `%APPDATA%\OctoPrint\logs\octoprint.log` on Windows and -`~/Library/Application Support/OctoPrint/logs/octoprint.log` on MacOS. Please -copy-paste this to pastebin or gist as well and include a link in your bug +`~/Library/Application Support/OctoPrint/logs/octoprint.log` on MacOS. You can +also access it directly through OctoPrint via Settings > Logs. Please +copy-paste this *completely* to pastebin or gist as well and include a link in your bug report. It might happen that you are asked to provide a more **thorough log of the @@ -383,6 +389,8 @@ the local version identifier to allow for an exact determination of the active c * 2016-03-14: Some more requirements for PRs, and a PR template. * 2016-06-08: New `prerelease` and `rc` branches explained. * 2016-09-09: New `rc/*` branches explained. + * 2016-09-23: Some more work on "How to file a bug report" based on recent + experiences ## Footnotes * [1] - If you are wondering why, the problem is that anything that you add diff --git a/README.md b/README.md index ae4f6369..47e9d7a2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -OctoPrint -========= +# OctoPrint OctoPrint provides a snappy web interface for controlling a 3D printer (RepRap, Ultimaker, ...). It is Free Software and released under the [GNU Affero General Public License V3](http://www.gnu.org/licenses/agpl.html). @@ -22,8 +21,7 @@ might be of more interest for you. You might also want to subscribe to [the mail or the [G+ Community](https://plus.google.com/communities/102771308349328485741) where there are other active users who might be able to help you with any questions you might have. -Contributing ------------- +## Contributing Contributions of all kinds are welcome, not only in the form of code but also with regards to the [official documentation](http://docs.octoprint.org/) or [the public wiki](https://github.com/foosel/OctoPrint/wiki), support @@ -31,15 +29,14 @@ of other users in the [bug tracker](https://github.com/foosel/OctoPrint/issues), [the Mailinglist](https://groups.google.com/group/octoprint) or [the G+ Community](https://plus.google.com/communities/102771308349328485741) and also [financially](http://octoprint.org/support-octoprint/). -If you think something is bad as it is about OctoPrint or its documentation the way it is, please help +If you think something is bad about OctoPrint or its documentation the way it is, please help in any way to make it better instead of just complaining about it -- this is an Open Source Project after all :) For information about how to go about contributions of any kind, please see the project's [Contribution Guidelines](https://github.com/foosel/OctoPrint/blob/master/CONTRIBUTING.md). -Installation ------------- +## Installation Installation instructions for installing from source for different operating systems can be found [on the wiki](https://github.com/foosel/OctoPrint/wiki#assorted-guides). @@ -66,8 +63,7 @@ releases but also be able to automatically upgrade to them from within OctoPrint, take a look [at the documentation of the Software Update Plugin](https://github.com/foosel/OctoPrint/wiki/Plugin:-Software-Update#making-octoprint-updateable-on-existing-installations) and at its settings. -Dependencies ------------- +## Dependencies OctoPrint depends on a couple of python modules to do its job. Those are automatically installed when installing OctoPrint via `setup.py`: @@ -78,8 +74,7 @@ You should also do this every time after pulling from the repository, since the OctoPrint currently only supports Python 2.7. -Usage ------ +## Usage Running the `setup.py` script via @@ -118,8 +113,7 @@ See `octoprint --help` for further information. OctoPrint also ships with a `run` script in its source directory. You can also invoke that to start up the server, it takes the same command line arguments as the `octoprint` script. -Configuration -------------- +## Configuration If not specified via the commandline, the configfile `config.yaml` for OctoPrint is expected in the settings folder, which is located at `~/.octoprint` on Linux, at `%APPDATA%/OctoPrint` on Windows and @@ -130,9 +124,7 @@ A comprehensive overview of all available configuration settings can be found Please note that the most commonly used configuration settings can also easily be edited from OctoPrint's settings dialog. -Special Thanks --------------- +## Special Thanks -The development of OctoPrint is sponsored and maintained by [BQ](http://www.bq.com/). Cross-browser testing services are kindly provided by [BrowserStack](http://www.browserstack.com/). Profiling is done with the help of [PyVmMonitor](http://www.pyvmmonitor.com). From 3d959c1d5f4709d99ef1d690543f559655ceaf1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Fri, 23 Sep 2016 12:29:56 +0200 Subject: [PATCH 2/5] maintenance branch is now 1.2.17.dev --- .versioneer-lookup | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.versioneer-lookup b/.versioneer-lookup index ed486827..d424da4d 100644 --- a/.versioneer-lookup +++ b/.versioneer-lookup @@ -16,11 +16,11 @@ prerelease HEAD \(detached.* -# maintenance is currently the branch for preparation of maintenance release 1.2.16 +# maintenance is currently the branch for preparation of maintenance release 1.2.17 # so are any fix/... and improve/... branches -maintenance 1.2.16 afdb98a92fb5dae2661aa252975933be55bef2c2 pep440-dev -fix/.* 1.2.16 afdb98a92fb5dae2661aa252975933be55bef2c2 pep440-dev -improve/.* 1.2.16 afdb98a92fb5dae2661aa252975933be55bef2c2 pep440-dev +maintenance 1.2.17 354042b84d488db38ac1917bb69bd164f4e7f750 pep440-dev +fix/.* 1.2.17 354042b84d488db38ac1917bb69bd164f4e7f750 pep440-dev +improve/.* 1.2.17 354042b84d488db38ac1917bb69bd164f4e7f750 pep440-dev # every other branch is a development branch and thus gets resolved to 1.3.0-dev for now .* 1.3.0 198d3450d94be1a2 pep440-dev From 3a13dd90220f591be83d03995b8759556a93af3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Fri, 23 Sep 2016 12:37:41 +0200 Subject: [PATCH 3/5] Fixed printerParameters config migrator Was marking the config as dirty just when printerParameters entry existed, which always exists - various sub entries of that are what needs to be checked instead. --- src/octoprint/settings.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 63c5cab5..df8bb3f0 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -666,6 +666,7 @@ class Settings(object): printer_parameters = self._config["printerParameters"] if "movementSpeed" in printer_parameters or "invertAxes" in printer_parameters: + dirty = True default_profile["axes"] = dict(x=dict(), y=dict(), z=dict(), e=dict()) if "movementSpeed" in printer_parameters: for axis in ("x", "y", "z", "e"): @@ -679,6 +680,7 @@ class Settings(object): del self._config["printerParameters"]["invertedAxes"] if "numExtruders" in printer_parameters or "extruderOffsets" in printer_parameters: + dirty = True if not "extruder" in default_profile: default_profile["extruder"] = dict() @@ -694,6 +696,7 @@ class Settings(object): del self._config["printerParameters"]["extruderOffsets"] if "bedDimensions" in printer_parameters: + dirty = True bed_dimensions = printer_parameters["bedDimensions"] if not "volume" in default_profile: default_profile["volume"] = dict() @@ -710,8 +713,6 @@ class Settings(object): default_profile["volume"]["depth"] = bed_dimensions["y"] del self._config["printerParameters"]["bedDimensions"] - dirty = True - if dirty: if not "printerProfiles" in self._config: self._config["printerProfiles"] = dict() From 080a6e9ccd284395567b9a2cae774143fc26408f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Fri, 23 Sep 2016 14:26:33 +0200 Subject: [PATCH 4/5] Extend atomic_write to allow setting & persisting file permissions --- src/octoprint/filemanager/__init__.py | 2 +- src/octoprint/plugins/cura/__init__.py | 2 +- .../plugins/softwareupdate/__init__.py | 2 +- src/octoprint/printer/profile.py | 2 +- src/octoprint/server/util/flask.py | 2 +- src/octoprint/settings.py | 4 +- src/octoprint/users.py | 2 +- src/octoprint/util/__init__.py | 7 +- tests/util/test_file_helpers.py | 104 +++++++++++++++++- 9 files changed, 114 insertions(+), 13 deletions(-) diff --git a/src/octoprint/filemanager/__init__.py b/src/octoprint/filemanager/__init__.py index ec4d1eea..0db223cc 100644 --- a/src/octoprint/filemanager/__init__.py +++ b/src/octoprint/filemanager/__init__.py @@ -427,7 +427,7 @@ class FileManager(object): pos=pos, date=time.time()) try: - with atomic_write(self._recovery_file) as f: + with atomic_write(self._recovery_file, max_permissions=0o666) as f: yaml.safe_dump(data, stream=f, default_flow_style=False, indent=" ", allow_unicode=True) except: self._logger.exception("Could not write recovery data to file {}".format(self._recovery_file)) diff --git a/src/octoprint/plugins/cura/__init__.py b/src/octoprint/plugins/cura/__init__.py index 0aa5cabc..bbce724f 100644 --- a/src/octoprint/plugins/cura/__init__.py +++ b/src/octoprint/plugins/cura/__init__.py @@ -391,7 +391,7 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin, def _save_profile(self, path, profile, allow_overwrite=True): import yaml - with octoprint.util.atomic_write(path, "wb") as f: + with octoprint.util.atomic_write(path, "wb", max_permissions=0o666) as f: yaml.safe_dump(profile, f, default_flow_style=False, indent=" ", allow_unicode=True) def _convert_to_engine(self, profile_path, printer_profile, posX, posY): diff --git a/src/octoprint/plugins/softwareupdate/__init__.py b/src/octoprint/plugins/softwareupdate/__init__.py index f391ad72..03c6e324 100644 --- a/src/octoprint/plugins/softwareupdate/__init__.py +++ b/src/octoprint/plugins/softwareupdate/__init__.py @@ -129,7 +129,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, octoprint_version = get_versions()["version"] self._version_cache["__version"] = octoprint_version - with atomic_write(self._version_cache_path) as file_obj: + with atomic_write(self._version_cache_path, max_permissions=0o666) as file_obj: yaml.safe_dump(self._version_cache, stream=file_obj, default_flow_style=False, indent=" ", allow_unicode=True) self._version_cache_dirty = False diff --git a/src/octoprint/printer/profile.py b/src/octoprint/printer/profile.py index 6102f523..52199c14 100644 --- a/src/octoprint/printer/profile.py +++ b/src/octoprint/printer/profile.py @@ -332,7 +332,7 @@ class PrinterProfileManager(object): from octoprint.util import atomic_write import yaml try: - with atomic_write(path, "wb") as f: + with atomic_write(path, "wb", max_permissions=0o666) as f: yaml.safe_dump(profile, f, default_flow_style=False, indent=" ", allow_unicode=True) except Exception as e: self._logger.exception("Error while trying to save profile %s" % profile["id"]) diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index 6ed17dcd..87c198b2 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -682,7 +682,7 @@ class PreemptiveCache(object): with self._lock: try: - with atomic_write(self.cachefile, "wb") as handle: + with atomic_write(self.cachefile, "wb", max_permissions=0o666) as handle: yaml.safe_dump(data, handle,default_flow_style=False, indent=" ", allow_unicode=True) except: self._logger.exception("Error while writing {}".format(self.cachefile)) diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index df8bb3f0..6076caf7 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -843,7 +843,7 @@ class Settings(object): from octoprint.util import atomic_write try: - with atomic_write(self._configfile, "wb", prefix="octoprint-config-", suffix=".yaml") as configFile: + with atomic_write(self._configfile, "wb", prefix="octoprint-config-", suffix=".yaml", permissions=0o600, max_permissions=0o666) as configFile: yaml.safe_dump(self._config, configFile, default_flow_style=False, indent=" ", allow_unicode=True) self._dirty = False except: @@ -1154,7 +1154,7 @@ class Settings(object): path, _ = os.path.split(filename) if not os.path.exists(path): os.makedirs(path) - with atomic_write(filename, "wb") as f: + with atomic_write(filename, "wb", max_permissions=0o666) as f: f.write(script) def _default_basedir(applicationName): diff --git a/src/octoprint/users.py b/src/octoprint/users.py index b6425dd7..11c23314 100644 --- a/src/octoprint/users.py +++ b/src/octoprint/users.py @@ -234,7 +234,7 @@ class FilebasedUserManager(UserManager): "settings": user._settings } - with atomic_write(self._userfile, "wb") as f: + with atomic_write(self._userfile, "wb", permissions=0o600, max_permissions=0o666) as f: yaml.safe_dump(data, f, default_flow_style=False, indent=" ", allow_unicode=True) self._dirty = False self._load() diff --git a/src/octoprint/util/__init__.py b/src/octoprint/util/__init__.py index f21a2006..97aa8a45 100644 --- a/src/octoprint/util/__init__.py +++ b/src/octoprint/util/__init__.py @@ -693,12 +693,17 @@ def address_for_client(host, port): @contextlib.contextmanager -def atomic_write(filename, mode="w+b", prefix="tmp", suffix=""): +def atomic_write(filename, mode="w+b", prefix="tmp", suffix="", permissions=0o644, max_permissions=0o777): + if os.path.exists(filename): + permissions |= os.stat(filename).st_mode + permissions &= max_permissions + temp_config = tempfile.NamedTemporaryFile(mode=mode, prefix=prefix, suffix=suffix, delete=False) try: yield temp_config finally: temp_config.close() + os.chmod(temp_config.name, permissions) shutil.move(temp_config.name, filename) diff --git a/tests/util/test_file_helpers.py b/tests/util/test_file_helpers.py index 160f776c..e0336488 100644 --- a/tests/util/test_file_helpers.py +++ b/tests/util/test_file_helpers.py @@ -83,13 +83,16 @@ class TestAtomicWrite(unittest.TestCase): @mock.patch("shutil.move") @mock.patch("tempfile.NamedTemporaryFile") - def test_atomic_write(self, mock_tempfile, mock_move): + @mock.patch("os.chmod") + @mock.patch("os.path.exists") + def test_atomic_write(self, mock_exists, mock_chmod, mock_tempfile, mock_move): """Tests the regular basic "good" case.""" # setup mock_file = mock.MagicMock() mock_file.name = "tempfile.tmp" mock_tempfile.return_value = mock_file + mock_exists.return_value = False # test with octoprint.util.atomic_write("somefile.yaml") as f: @@ -99,11 +102,14 @@ class TestAtomicWrite(unittest.TestCase): mock_tempfile.assert_called_once_with(mode="w+b", prefix="tmp", suffix="", delete=False) mock_file.write.assert_called_once_with("test") mock_file.close.assert_called_once_with() + mock_chmod.assert_called_once_with("tempfile.tmp", 0o644) mock_move.assert_called_once_with("tempfile.tmp", "somefile.yaml") @mock.patch("shutil.move") @mock.patch("tempfile.NamedTemporaryFile") - def test_atomic_write_error_on_write(self, mock_tempfile, mock_move): + @mock.patch("os.chmod") + @mock.patch("os.path.exists") + def test_atomic_write_error_on_write(self, mock_exists, mock_chmod, mock_tempfile, mock_move): """Tests the error case where something in the wrapped code fails.""" # setup @@ -111,6 +117,7 @@ class TestAtomicWrite(unittest.TestCase): mock_file.name = "tempfile.tmp" mock_file.write.side_effect = RuntimeError() mock_tempfile.return_value = mock_file + mock_exists.return_value = False # test try: @@ -124,16 +131,20 @@ class TestAtomicWrite(unittest.TestCase): mock_tempfile.assert_called_once_with(mode="w+b", prefix="tmp", suffix="", delete=False) mock_file.close.assert_called_once_with() self.assertFalse(mock_move.called) + self.assertFalse(mock_chmod.called) @mock.patch("shutil.move") @mock.patch("tempfile.NamedTemporaryFile") - def test_atomic_write_error_on_move(self, mock_tempfile, mock_move): + @mock.patch("os.chmod") + @mock.patch("os.path.exists") + def test_atomic_write_error_on_move(self, mock_exists, mock_chmod, mock_tempfile, mock_move): """Tests the error case where the final move fails.""" # setup mock_file = mock.MagicMock() mock_file.name = "tempfile.tmp" mock_tempfile.return_value = mock_file mock_move.side_effect = RuntimeError() + mock_exists.return_value = False # test try: @@ -147,16 +158,20 @@ class TestAtomicWrite(unittest.TestCase): mock_tempfile.assert_called_once_with(mode="w+b", prefix="tmp", suffix="", delete=False) mock_file.close.assert_called_once_with() self.assertTrue(mock_move.called) + self.assertTrue(mock_chmod.called) @mock.patch("shutil.move") @mock.patch("tempfile.NamedTemporaryFile") - def test_atomic_write_parameters(self, mock_tempfile, mock_move): + @mock.patch("os.chmod") + @mock.patch("os.path.exists") + def test_atomic_write_parameters(self, mock_exists, mock_chmod, mock_tempfile, mock_move): """Tests that the open parameters are propagated properly.""" # setup mock_file = mock.MagicMock() mock_file.name = "tempfile.tmp" mock_tempfile.return_value = mock_file + mock_exists.return_value = False # test with octoprint.util.atomic_write("somefile.yaml", mode="w", prefix="foo", suffix="bar") as f: @@ -165,6 +180,87 @@ class TestAtomicWrite(unittest.TestCase): # assert mock_tempfile.assert_called_once_with(mode="w", prefix="foo", suffix="bar", delete=False) mock_file.close.assert_called_once_with() + mock_chmod.assert_called_once_with("tempfile.tmp", 0o644) + mock_move.assert_called_once_with("tempfile.tmp", "somefile.yaml") + + + @mock.patch("shutil.move") + @mock.patch("tempfile.NamedTemporaryFile") + @mock.patch("os.chmod") + @mock.patch("os.path.exists") + def test_atomic_custom_permissions(self, mock_exists, mock_chmod, mock_tempfile, mock_move): + """Tests that custom permissions may be set.""" + + # setup + mock_file = mock.MagicMock() + mock_file.name = "tempfile.tmp" + mock_tempfile.return_value = mock_file + mock_exists.return_value = False + + # test + with octoprint.util.atomic_write("somefile.yaml", permissions=0o755) as f: + f.write("test") + + # assert + mock_tempfile.assert_called_once_with(mode="w+b", prefix="tmp", suffix="", delete=False) + mock_file.close.assert_called_once_with() + mock_chmod.assert_called_once_with("tempfile.tmp", 0o755) + mock_move.assert_called_once_with("tempfile.tmp", "somefile.yaml") + + @mock.patch("shutil.move") + @mock.patch("tempfile.NamedTemporaryFile") + @mock.patch("os.chmod") + @mock.patch("os.path.exists") + @mock.patch("os.stat") + def test_atomic_permissions_combined(self, mock_stat, mock_exists, mock_chmod, mock_tempfile, mock_move): + """Tests that the permissions of an existing file are combined with the requested permissions.""" + + # setup + mock_file = mock.MagicMock() + mock_file.name = "tempfile.tmp" + mock_tempfile.return_value = mock_file + mock_exists.return_value = True + + mock_stat_result = mock.MagicMock() + mock_stat_result.st_mode = 0o666 + mock_stat.return_value = mock_stat_result + + # test + with octoprint.util.atomic_write("somefile.yaml", permissions=0o755) as f: + f.write("test") + + # assert + mock_tempfile.assert_called_once_with(mode="w+b", prefix="tmp", suffix="", delete=False) + mock_file.close.assert_called_once_with() + mock_chmod.assert_called_once_with("tempfile.tmp", 0o777) # 0o755 | 0o666 + mock_move.assert_called_once_with("tempfile.tmp", "somefile.yaml") + + @mock.patch("shutil.move") + @mock.patch("tempfile.NamedTemporaryFile") + @mock.patch("os.chmod") + @mock.patch("os.path.exists") + @mock.patch("os.stat") + def test_atomic_permissions_limited(self, mock_stat, mock_exists, mock_chmod, mock_tempfile, mock_move): + """Tests that max_permissions limit the combined file permissions.""" + + # setup + mock_file = mock.MagicMock() + mock_file.name = "tempfile.tmp" + mock_tempfile.return_value = mock_file + mock_exists.return_value = True + + mock_stat_result = mock.MagicMock() + mock_stat_result.st_mode = 0o755 + mock_stat.return_value = mock_stat_result + + # test + with octoprint.util.atomic_write("somefile.yaml", permissions=0o600, max_permissions=0o666) as f: + f.write("test") + + # assert + mock_tempfile.assert_called_once_with(mode="w+b", prefix="tmp", suffix="", delete=False) + mock_file.close.assert_called_once_with() + mock_chmod.assert_called_once_with("tempfile.tmp", 0o644) # (0o600 | 0o755) & 0o666 = 0o755 & 0o666 mock_move.assert_called_once_with("tempfile.tmp", "somefile.yaml") From e700891dba5a12912d4944fd7973245b727ba538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Fri, 23 Sep 2016 14:26:58 +0200 Subject: [PATCH 5/5] Marked some paths for github's linguist --- .gitattributes | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitattributes b/.gitattributes index 6e546346..b0e3d15e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,10 @@ src/octoprint/_version.py export-subst + +src/octoprint/static/js/lib/* linguist-vendored +src/octoprint/static/less/bootstrap/* linguist-vendored +src/octoprint/static/less/font-awesome.less linguist-vendored +src/octoprint/static/less/mixins.less linguist-vendored +src/octoprint/static/less/variables.less linguist-vendored +versioneer.py linguist-vendored + +docs/* linguist-documentation