Add support for “globstar/**” (recursive) pattern

This commit is contained in:
Ivan Kravets
2020-05-26 14:25:28 +03:00
parent 6d32aeb310
commit 0eb8895959
7 changed files with 32 additions and 18 deletions

View File

@ -6,6 +6,11 @@ Release Notes
PlatformIO Core 4 PlatformIO Core 4
----------------- -----------------
4.3.5 (2020-??-??)
~~~~~~~~~~~~~~~~~~
* Added support for "globstar/`**`" (recursive) pattern for the different commands and configuration options (`platformio ci <https://docs.platformio.org/page/core/userguide/cmd_ci.html>`__, `src_filter <https://docs.platformio.org/page/projectconf/section_env_build.html#src-filter>`__, `check_patterns <https://docs.platformio.org/page/projectconf/section_env_check.html#check-patterns>`__, `library.json > srcFilter <https://docs.platformio.org/page/librarymanager/config.html#srcfilter>`__). Python 3.5+ is required.
4.3.4 (2020-05-23) 4.3.4 (2020-05-23)
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~

View File

@ -12,13 +12,12 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import glob
import os import os
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
import click import click
from platformio import fs, proc from platformio import compat, fs, proc
from platformio.commands.check.defect import DefectItem from platformio.commands.check.defect import DefectItem
from platformio.project.helpers import load_project_ide_data from platformio.project.helpers import load_project_ide_data
@ -183,7 +182,7 @@ class CheckToolBase(object): # pylint: disable=too-many-instance-attributes
result["c++"].append(os.path.realpath(path)) result["c++"].append(os.path.realpath(path))
for pattern in patterns: for pattern in patterns:
for item in glob.glob(pattern): for item in compat.glob_recursive(pattern):
if not os.path.isdir(item): if not os.path.isdir(item):
_add_file(item) _add_file(item)
for root, _, files in os.walk(item, followlinks=True): for root, _, files in os.walk(item, followlinks=True):

View File

@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from glob import glob
from os import getenv, makedirs, remove from os import getenv, makedirs, remove
from os.path import basename, isdir, isfile, join, realpath from os.path import basename, isdir, isfile, join, realpath
from shutil import copyfile, copytree from shutil import copyfile, copytree
@ -20,11 +19,10 @@ from tempfile import mkdtemp
import click import click
from platformio import app, fs from platformio import app, compat, fs
from platformio.commands.project import project_init as cmd_project_init from platformio.commands.project import project_init as cmd_project_init
from platformio.commands.project import validate_boards from platformio.commands.project import validate_boards
from platformio.commands.run.command import cli as cmd_run from platformio.commands.run.command import cli as cmd_run
from platformio.compat import glob_escape
from platformio.exception import CIBuildEnvsEmpty from platformio.exception import CIBuildEnvsEmpty
from platformio.project.config import ProjectConfig from platformio.project.config import ProjectConfig
@ -36,7 +34,7 @@ def validate_path(ctx, param, value): # pylint: disable=unused-argument
if p.startswith("~"): if p.startswith("~"):
value[i] = fs.expanduser(p) value[i] = fs.expanduser(p)
value[i] = realpath(value[i]) value[i] = realpath(value[i])
if not glob(value[i]): if not compat.glob_recursive(value[i]):
invalid_path = p invalid_path = p
break break
try: try:
@ -98,7 +96,7 @@ def cli( # pylint: disable=too-many-arguments, too-many-branches
continue continue
contents = [] contents = []
for p in patterns: for p in patterns:
contents += glob(p) contents += compat.glob_recursive(p)
_copy_contents(join(build_dir, dir_name), contents) _copy_contents(join(build_dir, dir_name), contents)
if project_conf and isfile(project_conf): if project_conf and isfile(project_conf):
@ -159,7 +157,7 @@ def _copy_contents(dst_dir, contents):
def _exclude_contents(dst_dir, patterns): def _exclude_contents(dst_dir, patterns):
contents = [] contents = []
for p in patterns: for p in patterns:
contents += glob(join(glob_escape(dst_dir), p)) contents += compat.glob_recursive(join(compat.glob_escape(dst_dir), p))
for path in contents: for path in contents:
path = realpath(path) path = realpath(path)
if isdir(path): if isdir(path):

View File

@ -14,7 +14,6 @@
from __future__ import absolute_import from __future__ import absolute_import
import glob
import io import io
import os import os
import shutil import shutil
@ -25,7 +24,7 @@ from twisted.internet import defer # pylint: disable=import-error
from platformio import app, fs, util from platformio import app, fs, util
from platformio.commands.home import helpers from platformio.commands.home import helpers
from platformio.compat import PY2, get_filesystem_encoding from platformio.compat import PY2, get_filesystem_encoding, glob_recursive
class OSRPC(object): class OSRPC(object):
@ -115,7 +114,9 @@ class OSRPC(object):
pathnames = [pathnames] pathnames = [pathnames]
result = set() result = set()
for pathname in pathnames: for pathname in pathnames:
result |= set(glob.glob(os.path.join(root, pathname) if root else pathname)) result |= set(
glob_recursive(os.path.join(root, pathname) if root else pathname)
)
return list(result) return list(result)
@staticmethod @staticmethod

View File

@ -15,6 +15,7 @@
# pylint: disable=unused-import, no-name-in-module, import-error, # pylint: disable=unused-import, no-name-in-module, import-error,
# pylint: disable=no-member, undefined-variable # pylint: disable=no-member, undefined-variable
import glob
import inspect import inspect
import json import json
import locale import locale
@ -81,6 +82,9 @@ if PY2:
_magic_check = re.compile("([*?[])") _magic_check = re.compile("([*?[])")
_magic_check_bytes = re.compile(b"([*?[])") _magic_check_bytes = re.compile(b"([*?[])")
def glob_recursive(pathname):
return glob.glob(pathname)
def glob_escape(pathname): def glob_escape(pathname):
"""Escape all special characters.""" """Escape all special characters."""
# https://github.com/python/cpython/blob/master/Lib/glob.py#L161 # https://github.com/python/cpython/blob/master/Lib/glob.py#L161
@ -122,6 +126,9 @@ else:
return obj return obj
return json.dumps(obj, ensure_ascii=False, sort_keys=True) return json.dumps(obj, ensure_ascii=False, sort_keys=True)
def glob_recursive(pathname):
return glob.glob(pathname, recursive=True)
def load_python_module(name, pathname): def load_python_module(name, pathname):
spec = importlib.util.spec_from_file_location(name, pathname) spec = importlib.util.spec_from_file_location(name, pathname)
module = importlib.util.module_from_spec(spec) module = importlib.util.module_from_spec(spec)

View File

@ -18,12 +18,11 @@ import re
import shutil import shutil
import stat import stat
import sys import sys
from glob import glob
import click import click
from platformio import exception from platformio import exception
from platformio.compat import WINDOWS, glob_escape from platformio.compat import WINDOWS, glob_escape, glob_recursive
class cd(object): class cd(object):
@ -135,7 +134,7 @@ def match_src_files(src_dir, src_filter=None, src_exts=None, followlinks=True):
src_filter = src_filter.replace("/", os.sep).replace("\\", os.sep) src_filter = src_filter.replace("/", os.sep).replace("\\", os.sep)
for (action, pattern) in re.findall(r"(\+|\-)<([^>]+)>", src_filter): for (action, pattern) in re.findall(r"(\+|\-)<([^>]+)>", src_filter):
items = set() items = set()
for item in glob(os.path.join(glob_escape(src_dir), pattern)): for item in glob_recursive(os.path.join(glob_escape(src_dir), pattern)):
if os.path.isdir(item): if os.path.isdir(item):
for root, _, files in os.walk(item, followlinks=followlinks): for root, _, files in os.walk(item, followlinks=followlinks):
for f in files: for f in files:

View File

@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import glob
import json import json
import os import os
import re import re
@ -21,7 +20,13 @@ from hashlib import sha1
import click import click
from platformio import fs from platformio import fs
from platformio.compat import PY2, WINDOWS, hashlib_encode_data, string_types from platformio.compat import (
PY2,
WINDOWS,
glob_recursive,
hashlib_encode_data,
string_types,
)
from platformio.project import exception from platformio.project import exception
from platformio.project.options import ProjectOptions from platformio.project.options import ProjectOptions
@ -117,7 +122,7 @@ class ProjectConfigBase(object):
for pattern in self.get("platformio", "extra_configs", []): for pattern in self.get("platformio", "extra_configs", []):
if pattern.startswith("~"): if pattern.startswith("~"):
pattern = fs.expanduser(pattern) pattern = fs.expanduser(pattern)
for item in glob.glob(pattern): for item in glob_recursive(pattern):
self.read(item) self.read(item)
def _maintain_renaimed_options(self): def _maintain_renaimed_options(self):