Fix deletion of unrendered timelapses

If the filename contained a [] pair, the file would not match the glob
pattern used for selecting for deletion.

Backporting the glob.escape function from Python 3.4 and using it here
should fix that. We only use our own ported version if glob.escape
doesn't exist - that should reduce redundant code once we become Python
3 compatible.
This commit is contained in:
Gina Häußge 2017-10-10 12:41:47 +02:00
parent b89b6970c6
commit abfcc6e5aa
3 changed files with 68 additions and 1 deletions

View file

@ -139,12 +139,14 @@ def get_unrendered_timelapses():
def delete_unrendered_timelapse(name):
global _cleanup_lock
pattern = "{}*.jpg".format(util.glob_escape(name))
basedir = settings().getBaseFolder("timelapse_tmp")
with _cleanup_lock:
for entry in scandir(basedir):
try:
if fnmatch.fnmatch(entry.name, "{}*.jpg".format(name)):
if fnmatch.fnmatch(entry.name, pattern):
os.remove(entry.path)
except:
if logging.getLogger(__name__).isEnabledFor(logging.DEBUG):

View file

@ -866,6 +866,29 @@ def is_hidden_path(path):
return False
try:
from glob import escape
glob_escape = escape
except ImportError:
# no glob.escape - we need to implement our own
_glob_escape_check = re.compile("([*?[])")
_glob_escape_check_bytes = re.compile(b"([*?[])")
def glob_escape(pathname):
"""
Ported from Python 3.4
See https://github.com/python/cpython/commit/fd32fffa5ada8b8be8a65bd51b001d989f99a3d3
"""
drive, pathname = os.path.splitdrive(pathname)
if isinstance(pathname, bytes):
pathname = _glob_escape_check_bytes.sub(br"[\1]", pathname)
else:
pathname = _glob_escape_check.sub(r"[\1]", pathname)
return drive + pathname
class RepeatedTimer(threading.Thread):
"""
This class represents an action that should be run repeatedly in an interval. It is similar to python's

View file

@ -358,3 +358,45 @@ class IsHiddenPathTest(unittest.TestCase):
def test_is_hidden_path(self, path_id, expected):
path = getattr(self, path_id) if path_id is not None else None
self.assertEqual(octoprint.util.is_hidden_path(path), expected)
try:
from glob import escape
except ImportError:
# no glob.escape - tests for our ported implementation
@ddt.ddt
class GlobEscapeTest(unittest.TestCase):
"""
Ported from Python 3.4
See https://github.com/python/cpython/commit/fd32fffa5ada8b8be8a65bd51b001d989f99a3d3
"""
@ddt.data(
("abc", "abc"),
("[", "[[]"),
("?", "[?]"),
("*", "[*]"),
("[[_/*?*/_]]", "[[][[]_/[*][?][*]/_]]"),
("/[[_/*?*/_]]/", "/[[][[]_/[*][?][*]/_]]/")
)
@ddt.unpack
def test_glob_escape(self, text, expected):
actual = octoprint.util.glob_escape(text)
self.assertEqual(actual, expected)
@ddt.data(
("?:?", "?:[?]"),
("*:*", "*:[*]"),
(r"\\?\c:\?", r"\\?\c:\[?]"),
(r"\\*\*\*", r"\\*\*\[*]"),
("//?/c:/?", "//?/c:/[?]"),
("//*/*/*", "//*/*/[*]")
)
@ddt.unpack
@unittest.skipUnless(sys.platform == "win32", "Win32 specific test")
def test_glob_escape_windows(self, text, expected):
actual = octoprint.util.glob_escape(text)
self.assertEqual(actual, expected)