forked from platformio/platformio-core
Improved support for projects located on a network share // Resolve #3417 , Resolve #3926 , Resolve #4102
This commit is contained in:
@ -11,6 +11,7 @@ PlatformIO Core 5
|
|||||||
5.2.4 (2021-??-??)
|
5.2.4 (2021-??-??)
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- Improved support for projects located on a network share (`issue #3417 <https://github.com/platformio/platformio-core/issues/3417>`_, `issue #3926 <https://github.com/platformio/platformio-core/issues/3926>`_, `issue #4099 <https://github.com/platformio/platformio-core/issues/4099>`_)
|
||||||
- Fixed an issue with the CLion project generator when a macro contains a space (`issue #4102 <https://github.com/platformio/platformio-core/issues/4102>`_)
|
- Fixed an issue with the CLion project generator when a macro contains a space (`issue #4102 <https://github.com/platformio/platformio-core/issues/4102>`_)
|
||||||
|
|
||||||
5.2.3 (2021-11-05)
|
5.2.3 (2021-11-05)
|
||||||
|
@ -31,7 +31,7 @@ from platformio.project.helpers import get_default_projects_dir
|
|||||||
|
|
||||||
def projects_dir_validate(projects_dir):
|
def projects_dir_validate(projects_dir):
|
||||||
assert os.path.isdir(projects_dir)
|
assert os.path.isdir(projects_dir)
|
||||||
return os.path.realpath(projects_dir)
|
return os.path.abspath(projects_dir)
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_SETTINGS = {
|
DEFAULT_SETTINGS = {
|
||||||
|
@ -128,15 +128,20 @@ env.Replace(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if int(ARGUMENTS.get("ISATTY", 0)):
|
||||||
compat.IS_WINDOWS
|
# pylint: disable=protected-access
|
||||||
and sys.version_info >= (3, 8)
|
click._compat.isatty = lambda stream: True
|
||||||
and env["PROJECT_DIR"].startswith("\\\\")
|
|
||||||
):
|
if compat.IS_WINDOWS and sys.version_info >= (3, 8) and os.getcwd().startswith("\\\\"):
|
||||||
|
click.secho("!!! WARNING !!!\t\t" * 3, fg="red")
|
||||||
click.secho(
|
click.secho(
|
||||||
"There is a known issue with Python 3.8+ and mapped network drives on "
|
"Your project is located on a mapped network drive but the "
|
||||||
"Windows.\nSee a solution at:\n"
|
"current command-line shell does not support the UNC paths.",
|
||||||
"https://github.com/platformio/platformio-core/issues/3417",
|
fg="yellow",
|
||||||
|
)
|
||||||
|
click.secho(
|
||||||
|
"Please move your project to a physical drive or check this workaround: "
|
||||||
|
"https://bit.ly/3kuU5mP\n",
|
||||||
fg="yellow",
|
fg="yellow",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -145,10 +150,6 @@ if env.subst("$BUILD_CACHE_DIR"):
|
|||||||
os.makedirs(env.subst("$BUILD_CACHE_DIR"))
|
os.makedirs(env.subst("$BUILD_CACHE_DIR"))
|
||||||
env.CacheDir("$BUILD_CACHE_DIR")
|
env.CacheDir("$BUILD_CACHE_DIR")
|
||||||
|
|
||||||
if int(ARGUMENTS.get("ISATTY", 0)):
|
|
||||||
# pylint: disable=protected-access
|
|
||||||
click._compat.isatty = lambda stream: True
|
|
||||||
|
|
||||||
is_clean_all = "cleanall" in COMMAND_LINE_TARGETS
|
is_clean_all = "cleanall" in COMMAND_LINE_TARGETS
|
||||||
if env.GetOption("clean") or is_clean_all:
|
if env.GetOption("clean") or is_clean_all:
|
||||||
env.PioClean(is_clean_all)
|
env.PioClean(is_clean_all)
|
||||||
|
@ -32,14 +32,14 @@ def _dump_includes(env):
|
|||||||
env.subst("$PROJECT_SRC_DIR"),
|
env.subst("$PROJECT_SRC_DIR"),
|
||||||
]
|
]
|
||||||
includes["build"].extend(
|
includes["build"].extend(
|
||||||
[os.path.realpath(env.subst(item)) for item in env.get("CPPPATH", [])]
|
[os.path.abspath(env.subst(item)) for item in env.get("CPPPATH", [])]
|
||||||
)
|
)
|
||||||
|
|
||||||
# installed libs
|
# installed libs
|
||||||
includes["compatlib"] = []
|
includes["compatlib"] = []
|
||||||
for lb in env.GetLibBuilders():
|
for lb in env.GetLibBuilders():
|
||||||
includes["compatlib"].extend(
|
includes["compatlib"].extend(
|
||||||
[os.path.realpath(inc) for inc in lb.get_include_dirs()]
|
[os.path.abspath(inc) for inc in lb.get_include_dirs()]
|
||||||
)
|
)
|
||||||
|
|
||||||
# includes from toolchains
|
# includes from toolchains
|
||||||
@ -56,9 +56,7 @@ def _dump_includes(env):
|
|||||||
os.path.join(toolchain_dir, "*", "include*"),
|
os.path.join(toolchain_dir, "*", "include*"),
|
||||||
]
|
]
|
||||||
for g in toolchain_incglobs:
|
for g in toolchain_incglobs:
|
||||||
includes["toolchain"].extend(
|
includes["toolchain"].extend([os.path.abspath(inc) for inc in glob.glob(g)])
|
||||||
[os.path.realpath(inc) for inc in glob.glob(g)]
|
|
||||||
)
|
|
||||||
|
|
||||||
# include Unity framework if there are tests in project
|
# include Unity framework if there are tests in project
|
||||||
includes["unity"] = []
|
includes["unity"] = []
|
||||||
@ -132,7 +130,7 @@ def _dump_defines(env):
|
|||||||
def _get_svd_path(env):
|
def _get_svd_path(env):
|
||||||
svd_path = env.GetProjectOption("debug_svd_path")
|
svd_path = env.GetProjectOption("debug_svd_path")
|
||||||
if svd_path:
|
if svd_path:
|
||||||
return os.path.realpath(svd_path)
|
return os.path.abspath(svd_path)
|
||||||
|
|
||||||
if "BOARD" not in env:
|
if "BOARD" not in env:
|
||||||
return None
|
return None
|
||||||
@ -147,7 +145,7 @@ def _get_svd_path(env):
|
|||||||
# default file from ./platform/misc/svd folder
|
# default file from ./platform/misc/svd folder
|
||||||
p = env.PioPlatform()
|
p = env.PioPlatform()
|
||||||
if os.path.isfile(os.path.join(p.get_dir(), "misc", "svd", svd_path)):
|
if os.path.isfile(os.path.join(p.get_dir(), "misc", "svd", svd_path)):
|
||||||
return os.path.realpath(os.path.join(p.get_dir(), "misc", "svd", svd_path))
|
return os.path.abspath(os.path.join(p.get_dir(), "misc", "svd", svd_path))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ class LibBuilderBase(object):
|
|||||||
def __init__(self, env, path, manifest=None, verbose=False):
|
def __init__(self, env, path, manifest=None, verbose=False):
|
||||||
self.env = env.Clone()
|
self.env = env.Clone()
|
||||||
self.envorigin = env.Clone()
|
self.envorigin = env.Clone()
|
||||||
self.path = os.path.realpath(env.subst(path))
|
self.path = os.path.abspath(env.subst(path))
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -290,7 +290,7 @@ class LibBuilderBase(object):
|
|||||||
if self.extra_script:
|
if self.extra_script:
|
||||||
self.env.SConscriptChdir(1)
|
self.env.SConscriptChdir(1)
|
||||||
self.env.SConscript(
|
self.env.SConscript(
|
||||||
os.path.realpath(self.extra_script),
|
os.path.abspath(self.extra_script),
|
||||||
exports={"env": self.env, "pio_lib_builder": self},
|
exports={"env": self.env, "pio_lib_builder": self},
|
||||||
)
|
)
|
||||||
self.env.ProcessUnFlags(self.build_unflags)
|
self.env.ProcessUnFlags(self.build_unflags)
|
||||||
@ -750,14 +750,14 @@ class PlatformIOLibBuilder(LibBuilderBase):
|
|||||||
def include_dir(self):
|
def include_dir(self):
|
||||||
if "includeDir" in self._manifest.get("build", {}):
|
if "includeDir" in self._manifest.get("build", {}):
|
||||||
with fs.cd(self.path):
|
with fs.cd(self.path):
|
||||||
return os.path.realpath(self._manifest.get("build").get("includeDir"))
|
return os.path.abspath(self._manifest.get("build").get("includeDir"))
|
||||||
return LibBuilderBase.include_dir.fget(self) # pylint: disable=no-member
|
return LibBuilderBase.include_dir.fget(self) # pylint: disable=no-member
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def src_dir(self):
|
def src_dir(self):
|
||||||
if "srcDir" in self._manifest.get("build", {}):
|
if "srcDir" in self._manifest.get("build", {}):
|
||||||
with fs.cd(self.path):
|
with fs.cd(self.path):
|
||||||
return os.path.realpath(self._manifest.get("build").get("srcDir"))
|
return os.path.abspath(self._manifest.get("build").get("srcDir"))
|
||||||
return LibBuilderBase.src_dir.fget(self) # pylint: disable=no-member
|
return LibBuilderBase.src_dir.fget(self) # pylint: disable=no-member
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -1024,7 +1024,7 @@ def GetLibBuilders(env): # pylint: disable=too-many-branches
|
|||||||
found_incompat = False
|
found_incompat = False
|
||||||
|
|
||||||
for storage_dir in env.GetLibSourceDirs():
|
for storage_dir in env.GetLibSourceDirs():
|
||||||
storage_dir = os.path.realpath(storage_dir)
|
storage_dir = os.path.abspath(storage_dir)
|
||||||
if not os.path.isdir(storage_dir):
|
if not os.path.isdir(storage_dir):
|
||||||
continue
|
continue
|
||||||
for item in sorted(os.listdir(storage_dir)):
|
for item in sorted(os.listdir(storage_dir)):
|
||||||
|
@ -376,7 +376,7 @@ def GetExtraScripts(env, scope):
|
|||||||
if not items:
|
if not items:
|
||||||
return items
|
return items
|
||||||
with fs.cd(env.subst("$PROJECT_DIR")):
|
with fs.cd(env.subst("$PROJECT_DIR")):
|
||||||
return [os.path.realpath(item) for item in items]
|
return [os.path.abspath(item) for item in items]
|
||||||
|
|
||||||
|
|
||||||
def exists(_):
|
def exists(_):
|
||||||
|
@ -207,12 +207,12 @@ def ParseFlagsExtended(env, flags): # pylint: disable=too-many-branches
|
|||||||
for k in ("CPPPATH", "LIBPATH"):
|
for k in ("CPPPATH", "LIBPATH"):
|
||||||
for i, p in enumerate(result.get(k, [])):
|
for i, p in enumerate(result.get(k, [])):
|
||||||
if os.path.isdir(p):
|
if os.path.isdir(p):
|
||||||
result[k][i] = os.path.realpath(p)
|
result[k][i] = os.path.abspath(p)
|
||||||
|
|
||||||
# fix relative path for "-include"
|
# fix relative path for "-include"
|
||||||
for i, f in enumerate(result.get("CCFLAGS", [])):
|
for i, f in enumerate(result.get("CCFLAGS", [])):
|
||||||
if isinstance(f, tuple) and f[0] == "-include":
|
if isinstance(f, tuple) and f[0] == "-include":
|
||||||
result["CCFLAGS"][i] = (f[0], env.File(os.path.realpath(f[1].get_path())))
|
result["CCFLAGS"][i] = (f[0], env.File(os.path.abspath(f[1].get_path())))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ class DefectItem(object):
|
|||||||
"severity": self.SEVERITY_LABELS[self.severity],
|
"severity": self.SEVERITY_LABELS[self.severity],
|
||||||
"category": self.category,
|
"category": self.category,
|
||||||
"message": self.message,
|
"message": self.message,
|
||||||
"file": os.path.realpath(self.file),
|
"file": os.path.abspath(self.file),
|
||||||
"line": self.line,
|
"line": self.line,
|
||||||
"column": self.column,
|
"column": self.column,
|
||||||
"callstack": self.callstack,
|
"callstack": self.callstack,
|
||||||
|
@ -201,11 +201,11 @@ class CheckToolBase(object): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
def _add_file(path):
|
def _add_file(path):
|
||||||
if path.endswith(header_extensions):
|
if path.endswith(header_extensions):
|
||||||
result["headers"].append(os.path.realpath(path))
|
result["headers"].append(os.path.abspath(path))
|
||||||
elif path.endswith(c_extension):
|
elif path.endswith(c_extension):
|
||||||
result["c"].append(os.path.realpath(path))
|
result["c"].append(os.path.abspath(path))
|
||||||
elif path.endswith(cpp_extensions):
|
elif path.endswith(cpp_extensions):
|
||||||
result["c++"].append(os.path.realpath(path))
|
result["c++"].append(os.path.abspath(path))
|
||||||
|
|
||||||
for pattern in patterns:
|
for pattern in patterns:
|
||||||
for item in glob.glob(pattern, recursive=True):
|
for item in glob.glob(pattern, recursive=True):
|
||||||
|
@ -33,7 +33,7 @@ def validate_path(ctx, param, value): # pylint: disable=unused-argument
|
|||||||
for i, p in enumerate(value):
|
for i, p in enumerate(value):
|
||||||
if p.startswith("~"):
|
if p.startswith("~"):
|
||||||
value[i] = fs.expanduser(p)
|
value[i] = fs.expanduser(p)
|
||||||
value[i] = os.path.realpath(value[i])
|
value[i] = os.path.abspath(value[i])
|
||||||
if not glob.glob(value[i], recursive=True):
|
if not glob.glob(value[i], recursive=True):
|
||||||
invalid_path = p
|
invalid_path = p
|
||||||
break
|
break
|
||||||
@ -162,7 +162,7 @@ def _exclude_contents(dst_dir, patterns):
|
|||||||
for p in patterns:
|
for p in patterns:
|
||||||
contents += glob.glob(os.path.join(glob.escape(dst_dir), p), recursive=True)
|
contents += glob.glob(os.path.join(glob.escape(dst_dir), p), recursive=True)
|
||||||
for path in contents:
|
for path in contents:
|
||||||
path = os.path.realpath(path)
|
path = os.path.abspath(path)
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
fs.rmtree(path)
|
fs.rmtree(path)
|
||||||
elif os.path.isfile(path):
|
elif os.path.isfile(path):
|
||||||
|
@ -93,7 +93,7 @@ class ProjectRPC:
|
|||||||
# skip non existing folders and resolve full path
|
# skip non existing folders and resolve full path
|
||||||
for key in ("envLibdepsDirs", "libExtraDirs"):
|
for key in ("envLibdepsDirs", "libExtraDirs"):
|
||||||
data[key] = [
|
data[key] = [
|
||||||
fs.expanduser(d) if d.startswith("~") else os.path.realpath(d)
|
fs.expanduser(d) if d.startswith("~") else os.path.abspath(d)
|
||||||
for d in data[key]
|
for d in data[key]
|
||||||
if os.path.isdir(d)
|
if os.path.isdir(d)
|
||||||
]
|
]
|
||||||
|
@ -61,7 +61,7 @@ class GDBClientProcess(DebugClientProcess):
|
|||||||
def _get_data_dir(gdb_path):
|
def _get_data_dir(gdb_path):
|
||||||
if "msp430" in gdb_path:
|
if "msp430" in gdb_path:
|
||||||
return None
|
return None
|
||||||
gdb_data_dir = os.path.realpath(
|
gdb_data_dir = os.path.abspath(
|
||||||
os.path.join(os.path.dirname(gdb_path), "..", "share", "gdb")
|
os.path.join(os.path.dirname(gdb_path), "..", "share", "gdb")
|
||||||
)
|
)
|
||||||
return gdb_data_dir if os.path.isdir(gdb_data_dir) else None
|
return gdb_data_dir if os.path.isdir(gdb_data_dir) else None
|
||||||
|
@ -24,7 +24,7 @@ import sys
|
|||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import exception
|
from platformio import exception, proc
|
||||||
from platformio.compat import IS_WINDOWS
|
from platformio.compat import IS_WINDOWS
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class cd(object):
|
|||||||
|
|
||||||
|
|
||||||
def get_source_dir():
|
def get_source_dir():
|
||||||
curpath = os.path.realpath(__file__)
|
curpath = os.path.abspath(__file__)
|
||||||
if not os.path.isfile(curpath):
|
if not os.path.isfile(curpath):
|
||||||
for p in sys.path:
|
for p in sys.path:
|
||||||
if os.path.isfile(os.path.join(p, __file__)):
|
if os.path.isfile(os.path.join(p, __file__)):
|
||||||
@ -119,7 +119,7 @@ def ensure_udev_rules():
|
|||||||
if not any(os.path.isfile(p) for p in installed_rules):
|
if not any(os.path.isfile(p) for p in installed_rules):
|
||||||
raise exception.MissedUdevRules
|
raise exception.MissedUdevRules
|
||||||
|
|
||||||
origin_path = os.path.realpath(
|
origin_path = os.path.abspath(
|
||||||
os.path.join(get_source_dir(), "..", "scripts", "99-platformio-udev.rules")
|
os.path.join(get_source_dir(), "..", "scripts", "99-platformio-udev.rules")
|
||||||
)
|
)
|
||||||
if not os.path.isfile(origin_path):
|
if not os.path.isfile(origin_path):
|
||||||
@ -181,6 +181,25 @@ def to_unix_path(path):
|
|||||||
return re.sub(r"[\\]+", "/", path)
|
return re.sub(r"[\\]+", "/", path)
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_path(path):
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
if not IS_WINDOWS or not path.startswith("\\\\"):
|
||||||
|
return path
|
||||||
|
try:
|
||||||
|
result = proc.exec_command(["net", "use"])
|
||||||
|
if result["returncode"] != 0:
|
||||||
|
return path
|
||||||
|
share_re = re.compile(r"\s([A-Z]\:)\s+(\\\\[^\s]+)")
|
||||||
|
for line in result["out"].split("\n"):
|
||||||
|
share = share_re.search(line)
|
||||||
|
if not share:
|
||||||
|
continue
|
||||||
|
path = path.replace(share.group(2), share.group(1))
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
def expanduser(path):
|
def expanduser(path):
|
||||||
"""
|
"""
|
||||||
Be compatible with Python 3.8, on Windows skip HOME and check for USERPROFILE
|
Be compatible with Python 3.8, on Windows skip HOME and check for USERPROFILE
|
||||||
|
@ -48,7 +48,7 @@ class LockFile(object):
|
|||||||
def __init__(self, path, timeout=LOCKFILE_TIMEOUT, delay=LOCKFILE_DELAY):
|
def __init__(self, path, timeout=LOCKFILE_TIMEOUT, delay=LOCKFILE_DELAY):
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.delay = delay
|
self.delay = delay
|
||||||
self._lock_path = os.path.realpath(path) + ".lock"
|
self._lock_path = os.path.abspath(path) + ".lock"
|
||||||
self._fp = None
|
self._fp = None
|
||||||
|
|
||||||
def _lock(self):
|
def _lock(self):
|
||||||
|
@ -252,9 +252,9 @@ class BasePackageManager( # pylint: disable=too-many-public-methods
|
|||||||
# external "URL" mismatch
|
# external "URL" mismatch
|
||||||
if spec.external:
|
if spec.external:
|
||||||
# local folder mismatch
|
# local folder mismatch
|
||||||
if os.path.realpath(spec.url) == os.path.realpath(pkg.path) or (
|
if os.path.abspath(spec.url) == os.path.abspath(pkg.path) or (
|
||||||
spec.url.startswith("file://")
|
spec.url.startswith("file://")
|
||||||
and os.path.realpath(pkg.path) == os.path.realpath(spec.url[7:])
|
and os.path.abspath(pkg.path) == os.path.abspath(spec.url[7:])
|
||||||
):
|
):
|
||||||
return True
|
return True
|
||||||
if spec.url != pkg.metadata.spec.url:
|
if spec.url != pkg.metadata.spec.url:
|
||||||
|
@ -82,7 +82,7 @@ class ProjectGenerator(object):
|
|||||||
"project_dir": self.project_dir,
|
"project_dir": self.project_dir,
|
||||||
"original_env_name": self.original_env_name,
|
"original_env_name": self.original_env_name,
|
||||||
"env_name": self.env_name,
|
"env_name": self.env_name,
|
||||||
"user_home_dir": os.path.realpath(fs.expanduser("~")),
|
"user_home_dir": os.path.abspath(fs.expanduser("~")),
|
||||||
"platformio_path": sys.argv[0]
|
"platformio_path": sys.argv[0]
|
||||||
if os.path.isfile(sys.argv[0])
|
if os.path.isfile(sys.argv[0])
|
||||||
else where_is_program("platformio"),
|
else where_is_program("platformio"),
|
||||||
@ -125,7 +125,9 @@ class ProjectGenerator(object):
|
|||||||
with fs.cd(self.project_dir):
|
with fs.cd(self.project_dir):
|
||||||
for root, _, files in os.walk(self.config.get("platformio", "src_dir")):
|
for root, _, files in os.walk(self.config.get("platformio", "src_dir")):
|
||||||
for f in files:
|
for f in files:
|
||||||
result.append(os.path.relpath(os.path.join(root, f)))
|
result.append(
|
||||||
|
os.path.relpath(os.path.join(os.path.realpath(root), f))
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_tpls(self):
|
def get_tpls(self):
|
||||||
|
@ -24,7 +24,7 @@ from platformio.project.config import ProjectConfig
|
|||||||
|
|
||||||
|
|
||||||
def get_project_dir():
|
def get_project_dir():
|
||||||
return os.getcwd()
|
return fs.normalize_path(os.getcwd())
|
||||||
|
|
||||||
|
|
||||||
def is_platformio_project(project_dir=None):
|
def is_platformio_project(project_dir=None):
|
||||||
|
@ -114,7 +114,7 @@ def validate_dir(path):
|
|||||||
path = fs.expanduser(path)
|
path = fs.expanduser(path)
|
||||||
if "$" in path:
|
if "$" in path:
|
||||||
path = expand_dir_templates(path)
|
path = expand_dir_templates(path)
|
||||||
return os.path.realpath(path)
|
return fs.normalize_path(path)
|
||||||
|
|
||||||
|
|
||||||
def validate_core_dir(path):
|
def validate_core_dir(path):
|
||||||
|
Reference in New Issue
Block a user