Files
platformio-core/platformio/project/helpers.py

223 lines
6.9 KiB
Python

# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
from hashlib import sha1
from os import walk
from os.path import (basename, dirname, expanduser, isdir, isfile, join,
realpath, splitdrive)
from click.testing import CliRunner
from platformio import __version__, exception
from platformio.compat import WINDOWS, hashlib_encode_data
from platformio.project.config import ProjectConfig
def get_project_dir():
return os.getcwd()
def is_platformio_project(project_dir=None):
if not project_dir:
project_dir = get_project_dir()
return isfile(join(project_dir, "platformio.ini"))
def find_project_dir_above(path):
if isfile(path):
path = dirname(path)
if is_platformio_project(path):
return path
if isdir(dirname(path)):
return find_project_dir_above(dirname(path))
return None
def get_project_optional_dir(name, default=None):
project_dir = get_project_dir()
config = ProjectConfig.get_instance(join(project_dir, "platformio.ini"))
optional_dir = config.get("platformio", name)
if not optional_dir:
return default
if "$PROJECT_HASH" in optional_dir:
optional_dir = optional_dir.replace(
"$PROJECT_HASH", "%s-%s" %
(basename(project_dir), sha1(
hashlib_encode_data(project_dir)).hexdigest()[:10]))
if optional_dir.startswith("~"):
optional_dir = expanduser(optional_dir)
return realpath(optional_dir)
def get_project_core_dir():
default = join(expanduser("~"), ".platformio")
core_dir = get_project_optional_dir(
"core_dir", get_project_optional_dir("home_dir", default))
win_core_dir = None
if WINDOWS and core_dir == default:
win_core_dir = splitdrive(core_dir)[0] + "\\.platformio"
if isdir(win_core_dir):
core_dir = win_core_dir
if not isdir(core_dir):
try:
os.makedirs(core_dir)
except OSError as e:
if win_core_dir:
os.makedirs(win_core_dir)
core_dir = win_core_dir
else:
raise e
assert isdir(core_dir)
return core_dir
def get_project_global_lib_dir():
return get_project_optional_dir("globallib_dir",
join(get_project_core_dir(), "lib"))
def get_project_platforms_dir():
return get_project_optional_dir("platforms_dir",
join(get_project_core_dir(), "platforms"))
def get_project_packages_dir():
return get_project_optional_dir("packages_dir",
join(get_project_core_dir(), "packages"))
def get_project_cache_dir():
return get_project_optional_dir("cache_dir",
join(get_project_core_dir(), ".cache"))
def get_project_workspace_dir():
return get_project_optional_dir("workspace_dir",
join(get_project_dir(), ".pio"))
def get_project_build_dir(force=False):
path = get_project_optional_dir("build_dir",
join(get_project_workspace_dir(), "build"))
try:
if not isdir(path):
os.makedirs(path)
except Exception as e: # pylint: disable=broad-except
if not force:
raise Exception(e)
return path
def get_project_libdeps_dir():
return get_project_optional_dir(
"libdeps_dir", join(get_project_workspace_dir(), "libdeps"))
def get_project_lib_dir():
return get_project_optional_dir("lib_dir", join(get_project_dir(), "lib"))
def get_project_include_dir():
return get_project_optional_dir("include_dir",
join(get_project_dir(), "include"))
def get_project_src_dir():
return get_project_optional_dir("src_dir", join(get_project_dir(), "src"))
def get_project_test_dir():
return get_project_optional_dir("test_dir", join(get_project_dir(),
"test"))
def get_project_boards_dir():
return get_project_optional_dir("boards_dir",
join(get_project_dir(), "boards"))
def get_project_data_dir():
return get_project_optional_dir("data_dir", join(get_project_dir(),
"data"))
def get_project_shared_dir():
return get_project_optional_dir("shared_dir",
join(get_project_dir(), "shared"))
def compute_project_checksum(config):
# rebuild when PIO Core version changes
checksum = sha1(hashlib_encode_data(__version__))
# configuration file state
checksum.update(hashlib_encode_data(config.to_json()))
# project file structure
check_suffixes = (".c", ".cc", ".cpp", ".h", ".hpp", ".s", ".S")
for d in (get_project_include_dir(), get_project_src_dir(),
get_project_lib_dir()):
if not isdir(d):
continue
chunks = []
for root, _, files in walk(d):
for f in files:
path = join(root, f)
if path.endswith(check_suffixes):
chunks.append(path)
if not chunks:
continue
chunks_to_str = ",".join(sorted(chunks))
if WINDOWS: # case insensitive OS
chunks_to_str = chunks_to_str.lower()
checksum.update(hashlib_encode_data(chunks_to_str))
return checksum.hexdigest()
def load_project_ide_data(project_dir, envs):
from platformio.commands.run import cli as cmd_run
assert envs
if not isinstance(envs, (list, tuple)):
envs = [envs]
args = ["--project-dir", project_dir, "--target", "idedata"]
for env in envs:
args.extend(["-e", env])
result = CliRunner().invoke(cmd_run, args)
if result.exit_code != 0 and not isinstance(result.exception,
exception.ReturnErrorCode):
raise result.exception
if '"includes":' not in result.output:
raise exception.PlatformioException(result.output)
data = {}
for line in result.output.split("\n"):
line = line.strip()
if (line.startswith('{"') and line.endswith("}")
and "env_name" in line):
_data = json.loads(line)
if "env_name" in _data:
data[_data['env_name']] = _data
if len(envs) == 1 and envs[0] in data:
return data[envs[0]]
return data or None