Improved computing of project check sum (structure, configuration) and avoid unnecessary rebuilding

This commit is contained in:
Ivan Kravets
2019-07-16 15:47:33 +03:00
parent 71c4201487
commit 8059e04499
5 changed files with 42 additions and 35 deletions

View File

@ -11,6 +11,7 @@ PlatformIO 4.0
* Print `debug tool <http://docs.platformio.org/en/latest/plus/debugging.html#tools-debug-probes>`__ name for the active debugging session * Print `debug tool <http://docs.platformio.org/en/latest/plus/debugging.html#tools-debug-probes>`__ name for the active debugging session
* Do not shutdown PIO Home Server for "upgrade" operations (`issue #2784 <https://github.com/platformio/platformio-core/issues/2784>`_) * Do not shutdown PIO Home Server for "upgrade" operations (`issue #2784 <https://github.com/platformio/platformio-core/issues/2784>`_)
* Improved computing of project check sum (structure, configuration) and avoid unnecessary rebuilding
* Fixed an issue with incorrect escaping of Windows slashes when using `PIO Unified Debugger <http://docs.platformio.org/en/latest/plus/debugging.html>`__ and "piped" openOCD * Fixed an issue with incorrect escaping of Windows slashes when using `PIO Unified Debugger <http://docs.platformio.org/en/latest/plus/debugging.html>`__ and "piped" openOCD
4.0.0 (2019-07-10) 4.0.0 (2019-07-10)

View File

@ -74,10 +74,14 @@ def cli(ctx, environment, target, upload_port, project_dir, project_conf, jobs,
project_dir = find_project_dir_above(project_dir) project_dir = find_project_dir_above(project_dir)
with util.cd(project_dir): with util.cd(project_dir):
config = ProjectConfig.get_instance(
project_conf or join(project_dir, "platformio.ini"))
config.validate(environment)
# clean obsolete build dir # clean obsolete build dir
if not disable_auto_clean: if not disable_auto_clean:
try: try:
clean_build_dir(get_project_build_dir()) clean_build_dir(get_project_build_dir(), config)
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
click.secho( click.secho(
"Can not remove temporary directory `%s`. Please remove " "Can not remove temporary directory `%s`. Please remove "
@ -85,10 +89,6 @@ def cli(ctx, environment, target, upload_port, project_dir, project_conf, jobs,
get_project_build_dir(force=True), get_project_build_dir(force=True),
fg="yellow") fg="yellow")
config = ProjectConfig.get_instance(
project_conf or join(project_dir, "platformio.ini"))
config.validate(environment)
handle_legacy_libdeps(project_dir, config) handle_legacy_libdeps(project_dir, config)
results = [] results = []

View File

@ -13,13 +13,13 @@
# limitations under the License. # limitations under the License.
from os import makedirs from os import makedirs
from os.path import getmtime, isdir, isfile, join from os.path import isdir, isfile, join
from time import time from time import time
import click import click
from platformio import util from platformio import util
from platformio.project.helpers import (calculate_project_hash, from platformio.project.helpers import (compute_project_checksum,
get_project_dir, get_project_dir,
get_project_libdeps_dir) get_project_libdeps_dir)
@ -43,32 +43,26 @@ def handle_legacy_libdeps(project_dir, config):
fg="yellow") fg="yellow")
def clean_build_dir(build_dir): def clean_build_dir(build_dir, config):
# remove legacy ".pioenvs" folder # remove legacy ".pioenvs" folder
legacy_build_dir = join(get_project_dir(), ".pioenvs") legacy_build_dir = join(get_project_dir(), ".pioenvs")
if isdir(legacy_build_dir) and legacy_build_dir != build_dir: if isdir(legacy_build_dir) and legacy_build_dir != build_dir:
util.rmtree_(legacy_build_dir) util.rmtree_(legacy_build_dir)
structhash_file = join(build_dir, "structure.hash") checksum_file = join(build_dir, "project.checksum")
proj_hash = calculate_project_hash() checksum = compute_project_checksum(config)
# if project's config is modified if isdir(build_dir):
if (isdir(build_dir) and getmtime(join( # check project structure
get_project_dir(), "platformio.ini")) > getmtime(build_dir)): if isfile(checksum_file):
with open(checksum_file) as f:
if f.read() == checksum:
return
util.rmtree_(build_dir) util.rmtree_(build_dir)
# check project structure makedirs(build_dir)
if isdir(build_dir) and isfile(structhash_file): with open(checksum_file, "w") as f:
with open(structhash_file) as f: f.write(checksum)
if f.read() == proj_hash:
return
util.rmtree_(build_dir)
if not isdir(build_dir):
makedirs(build_dir)
with open(structhash_file, "w") as f:
f.write(proj_hash)
def print_header(label, is_error=False, fg=None): def print_header(label, is_error=False, fg=None):

View File

@ -16,7 +16,7 @@ import glob
import json import json
import os import os
import re import re
from os.path import isfile from os.path import expanduser, isfile
import click import click
@ -106,6 +106,8 @@ class ProjectConfig(object):
# load extra configs # load extra configs
for pattern in self.get("platformio", "extra_configs", []): for pattern in self.get("platformio", "extra_configs", []):
if pattern.startswith("~"):
pattern = expanduser(pattern)
for item in glob.glob(pattern): for item in glob.glob(pattern):
self.read(item) self.read(item)

View File

@ -165,23 +165,33 @@ def get_project_shared_dir():
join(get_project_dir(), "shared")) join(get_project_dir(), "shared"))
def calculate_project_hash(): def compute_project_checksum(config):
# rebuild when PIO Core version changes
checksum = sha1(__version__)
# configuration file state
checksum.update(hashlib_encode_data(config.to_json()))
# project file structure
check_suffixes = (".c", ".cc", ".cpp", ".h", ".hpp", ".s", ".S") check_suffixes = (".c", ".cc", ".cpp", ".h", ".hpp", ".s", ".S")
chunks = [__version__] for d in (get_project_include_dir(), get_project_src_dir(),
for d in (get_project_src_dir(), get_project_lib_dir()): get_project_lib_dir()):
if not isdir(d): if not isdir(d):
continue continue
chunks = []
for root, _, files in walk(d): for root, _, files in walk(d):
for f in files: for f in files:
path = join(root, f) path = join(root, f)
if path.endswith(check_suffixes): if path.endswith(check_suffixes):
chunks.append(path) chunks.append(path)
chunks_to_str = ",".join(sorted(chunks)) if not chunks:
if WINDOWS: continue
# Fix issue with useless project rebuilding for case insensitive FS. chunks_to_str = ",".join(sorted(chunks))
# A case of disk drive can differ... if WINDOWS: # case insensitive OS
chunks_to_str = chunks_to_str.lower() chunks_to_str = chunks_to_str.lower()
return sha1(hashlib_encode_data(chunks_to_str)).hexdigest() checksum.update(hashlib_encode_data(chunks_to_str))
return checksum.hexdigest()
def load_project_ide_data(project_dir, env_name): def load_project_ide_data(project_dir, env_name):