diff --git a/platformio/builder/tools/pioide.py b/platformio/builder/tools/pioide.py index 311b0203..c6d8fbc0 100644 --- a/platformio/builder/tools/pioide.py +++ b/platformio/builder/tools/pioide.py @@ -21,6 +21,7 @@ from os.path import abspath, isfile, join from SCons.Defaults import processDefines # pylint: disable=import-error from platformio import util +from platformio.compat import glob_escape from platformio.managers.core import get_core_package_dir from platformio.proc import exec_command @@ -40,7 +41,7 @@ def _dump_includes(env): for name in p.get_installed_packages(): if p.get_package_type(name) != "toolchain": continue - toolchain_dir = util.glob_escape(p.get_package_dir(name)) + toolchain_dir = glob_escape(p.get_package_dir(name)) toolchain_incglobs = [ join(toolchain_dir, "*", "include*"), join(toolchain_dir, "*", "include", "c++", "*"), diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index a5b277cd..2f38e649 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -33,7 +33,7 @@ from SCons.Script import DefaultEnvironment # pylint: disable=import-error from platformio import exception, util from platformio.builder.tools import platformio as piotool -from platformio.compat import PY2, WINDOWS, string_types +from platformio.compat import PY2, WINDOWS, get_file_contents, string_types from platformio.managers.lib import LibraryManager from platformio.managers.package import PackageManager @@ -80,7 +80,7 @@ class LibBuilderFactory(object): if not env.IsFileWithExt( fname, piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT): continue - content = util.get_file_contents(join(root, fname)) + content = get_file_contents(join(root, fname)) if not content: continue if "Arduino.h" in content and include_re.search(content): diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 19768146..bfc41a76 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -25,6 +25,7 @@ from SCons.Action import Action # pylint: disable=import-error from SCons.Script import ARGUMENTS # pylint: disable=import-error from platformio import util +from platformio.compat import get_file_contents, glob_escape from platformio.managers.core import get_core_package_dir from platformio.proc import exec_command @@ -59,7 +60,7 @@ class InoToCPPConverter(object): assert nodes lines = [] for node in nodes: - contents = util.get_file_contents(node.get_path()) + contents = get_file_contents(node.get_path()) _lines = [ '# 1 "%s"' % node.get_path().replace("\\", "/"), contents ] @@ -77,7 +78,7 @@ class InoToCPPConverter(object): def process(self, contents): out_file = self._main_ino + ".cpp" assert self._gcc_preprocess(contents, out_file) - contents = util.get_file_contents(out_file) + contents = get_file_contents(out_file) contents = self._join_multiline_strings(contents) with open(out_file, "w") as fp: fp.write(self.append_prototypes(contents)) @@ -188,7 +189,7 @@ class InoToCPPConverter(object): def ConvertInoToCpp(env): - src_dir = util.glob_escape(env.subst("$PROJECTSRC_DIR")) + src_dir = glob_escape(env.subst("$PROJECTSRC_DIR")) ino_nodes = ( env.Glob(join(src_dir, "*.ino")) + env.Glob(join(src_dir, "*.pde"))) if not ino_nodes: diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index a8272b83..3a0347c4 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -27,8 +27,8 @@ from SCons.Script import DefaultEnvironment # pylint: disable=import-error from SCons.Script import Export # pylint: disable=import-error from SCons.Script import SConscript # pylint: disable=import-error -from platformio.compat import string_types -from platformio.util import glob_escape, pioversion_to_intstr +from platformio.compat import glob_escape, string_types +from platformio.util import pioversion_to_intstr SRC_HEADER_EXT = ["h", "hpp"] SRC_C_EXT = ["c", "cc", "cpp"] diff --git a/platformio/commands/ci.py b/platformio/commands/ci.py index 9fd157e3..7d97eb48 100644 --- a/platformio/commands/ci.py +++ b/platformio/commands/ci.py @@ -24,6 +24,7 @@ from platformio import app, util from platformio.commands.init import cli as cmd_init from platformio.commands.init import validate_boards from platformio.commands.run import cli as cmd_run +from platformio.compat import glob_escape from platformio.exception import CIBuildEnvsEmpty from platformio.project.config import ProjectConfig @@ -152,7 +153,7 @@ def _copy_contents(dst_dir, contents): def _exclude_contents(dst_dir, patterns): contents = [] for p in patterns: - contents += glob(join(util.glob_escape(dst_dir), p)) + contents += glob(join(glob_escape(dst_dir), p)) for path in contents: path = abspath(path) if isdir(path): diff --git a/platformio/commands/remote.py b/platformio/commands/remote.py index b37e843c..ded45eda 100644 --- a/platformio/commands/remote.py +++ b/platformio/commands/remote.py @@ -23,6 +23,7 @@ import click from platformio import exception, util from platformio.commands.device import device_monitor as cmd_device_monitor +from platformio.compat import get_file_contents from platformio.managers.core import pioplus_call # pylint: disable=unused-argument @@ -206,7 +207,7 @@ def device_monitor(ctx, **kwargs): sleep(0.1) if not t.is_alive(): return - kwargs['port'] = util.get_file_contents(sock_file) + kwargs['port'] = get_file_contents(sock_file) ctx.invoke(cmd_device_monitor, **kwargs) t.join(2) finally: diff --git a/platformio/compat.py b/platformio/compat.py index cd50d905..3c3afc52 100644 --- a/platformio/compat.py +++ b/platformio/compat.py @@ -12,6 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=unused-import + +import os +import re import sys PY2 = sys.version_info[0] == 2 @@ -32,7 +36,29 @@ if PY2: def path_to_unicode(path): return path.decode(get_filesystem_encoding()).encode("utf-8") + + def get_file_contents(path): + with open(path) as f: + return f.read() + + _magic_check = re.compile('([*?[])') + _magic_check_bytes = re.compile(b'([*?[])') + + def glob_escape(pathname): + """Escape all special characters.""" + # https://github.com/python/cpython/blob/master/Lib/glob.py#L161 + # 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 else: + from glob import escape as glob_escape # pylint: disable=no-name-in-module + string_types = (str, ) def is_bytes(x): @@ -40,3 +66,11 @@ else: def path_to_unicode(path): return path + + def get_file_contents(path): + try: + with open(path) as f: + return f.read() + except UnicodeDecodeError: + with open(path, encoding="latin-1") as f: + return f.read() diff --git a/platformio/ide/projectgenerator.py b/platformio/ide/projectgenerator.py index 1216aaee..37d0db53 100644 --- a/platformio/ide/projectgenerator.py +++ b/platformio/ide/projectgenerator.py @@ -23,7 +23,7 @@ from click.testing import CliRunner from platformio import exception, util from platformio.commands.run import cli as cmd_run -from platformio.compat import PY2, WINDOWS +from platformio.compat import PY2, WINDOWS, get_file_contents from platformio.project.config import ProjectConfig from platformio.project.helpers import ( get_projectlib_dir, get_projectlibdeps_dir, get_projectsrc_dir) @@ -124,8 +124,7 @@ class ProjectGenerator(object): contents.encode("utf8") if PY2 else contents) def _render_tpl(self, tpl_path): - return bottle.template( - util.get_file_contents(tpl_path), **self._tplvars) + return bottle.template(get_file_contents(tpl_path), **self._tplvars) @staticmethod def _merge_contents(dst_path, contents): diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index b478f49c..ca143b58 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -23,7 +23,7 @@ from os.path import isdir, join import click from platformio import app, commands, exception, util -from platformio.compat import string_types +from platformio.compat import glob_escape, string_types from platformio.managers.package import BasePkgManager from platformio.managers.platform import PlatformFactory, PlatformManager @@ -48,7 +48,7 @@ class LibraryManager(BasePkgManager): return path # if library without manifest, returns first source file - src_dir = join(util.glob_escape(pkg_dir)) + src_dir = join(glob_escape(pkg_dir)) if isdir(join(pkg_dir, "src")): src_dir = join(src_dir, "src") chs_files = glob(join(src_dir, "*.[chS]")) diff --git a/platformio/util.py b/platformio/util.py index 83552d6b..5de68256 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -33,7 +33,7 @@ import click import requests from platformio import __apiurl__, __version__, exception -from platformio.compat import PY2, WINDOWS, path_to_unicode +from platformio.compat import PY2, WINDOWS, get_file_contents, path_to_unicode from platformio.proc import LineBufferedAsyncPipe as AsyncPipe from platformio.proc import exec_command, is_ci, where_is_program from platformio.project.config import ProjectConfig @@ -523,15 +523,6 @@ def merge_dicts(d1, d2, path=None): return d1 -def get_file_contents(path): - try: - with open(path) as f: - return f.read() - except UnicodeDecodeError: - with open(path, encoding="latin-1") as f: - return f.read() - - def ensure_udev_rules(): def _rules_to_set(rules_path): @@ -588,27 +579,3 @@ def rmtree_(path): err=True) 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