diff --git a/HISTORY.rst b/HISTORY.rst index e5496560..4df920b0 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -28,6 +28,7 @@ PlatformIO 3.0 (`issue #850 `_) * Use C++11 by default for CLion IDE based projects (`pull #873 `_) +* Escape project path when Glob matching is used ------- diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 3b9f34e8..2aa259e3 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -181,8 +181,9 @@ class InoToCPPConverter(object): def ConvertInoToCpp(env): - ino_nodes = (env.Glob(join("$PROJECTSRC_DIR", "*.ino")) + - env.Glob(join("$PROJECTSRC_DIR", "*.pde"))) + src_dir = util.glob_escape(env.subst("$PROJECTSRC_DIR")) + ino_nodes = ( + env.Glob(join(src_dir, "*.ino")) + env.Glob(join(src_dir, "*.pde"))) if not ino_nodes: return c = InoToCPPConverter(env) @@ -216,7 +217,7 @@ def DumpIDEData(env): for name in p.get_installed_packages(): if p.get_package_type(name) != "toolchain": continue - toolchain_dir = p.get_package_dir(name) + toolchain_dir = util.glob_escape(p.get_package_dir(name)) toolchain_incglobs = [ join(toolchain_dir, "*", "include*"), join(toolchain_dir, "lib", "gcc", "*", "*", "include*") diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index fa39934f..56875c1a 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -25,7 +25,7 @@ from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, DefaultEnvironment, SConscript) from SCons.Util import case_sensitive_suffixes, is_Sequence -from platformio.util import pioversion_to_intstr +from platformio.util import glob_escape, pioversion_to_intstr SRC_BUILD_EXT = ["c", "cpp", "S", "spp", "SPP", "sx", "s", "asm", "ASM"] SRC_HEADER_EXT = ["h", "hpp"] @@ -191,7 +191,7 @@ def MatchSourceFiles(env, src_dir, src_filter=None): src_filter = src_filter.replace("/", sep).replace("\\", sep) for (action, pattern) in SRC_FILTER_PATTERNS_RE.findall(src_filter): items = set() - for item in glob(join(src_dir, pattern)): + for item in glob(join(glob_escape(src_dir), pattern)): if isdir(item): for root, _, files in walk(item, followlinks=True): for f in files: diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index e74abb18..82784eb4 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -152,7 +152,7 @@ def _copy_contents(dst_dir, contents): def _exclude_contents(dst_dir, patterns): contents = [] for p in patterns: - contents += glob(join(dst_dir, p)) + contents += glob(join(util.glob_escape(dst_dir), p)) for path in contents: path = abspath(path) if isdir(path): diff --git a/platformio/util.py b/platformio/util.py index c2fe8653..b3406dbf 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -568,3 +568,28 @@ def rmtree_(path): os.remove(name) return rmtree(path, onerror=_onerror) + + +# +# Glob.Escape from Python 3.4 +# https://github.com/python/cpython/blob/master/Lib/glob.py#L161 +# + +try: + from glob import escape as glob_escape # pylint: disable=unused-import +except ImportError: + magic_check = re.compile('([*?[])') + magic_check_bytes = re.compile(b'([*?[])') + + def glob_escape(pathname): + """Escape all special characters. + """ + # Escaping is done by wrapping any of "*?[" between square brackets. + # Metacharacters do not work in the drive part and shouldn't be + # escaped. + drive, pathname = os.path.splitdrive(pathname) + if isinstance(pathname, bytes): + pathname = magic_check_bytes.sub(br'[\1]', pathname) + else: + pathname = magic_check.sub(r'[\1]', pathname) + return drive + pathname