mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(tools/cmake): Added VERSION argument to the project() macro in cmake
This commit enables the standad VERSION argument for the project() macro in ESP-IDF. The VERSION argument is compilant with the requirements of cmake 3.16. This commit also adds new test cases for verifying the validity of the version argument. Merges https://github.com/espressif/esp-idf/pull/12461 Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
This commit is contained in:
parent
105f6dd22c
commit
9beda4ce48
@ -18,7 +18,7 @@ if(NOT BOOTLOADER_BUILD)
|
|||||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_app_desc")
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_app_desc")
|
||||||
|
|
||||||
if(CONFIG_APP_PROJECT_VER_FROM_CONFIG)
|
if(CONFIG_APP_PROJECT_VER_FROM_CONFIG)
|
||||||
# Ignore current PROJECT_VER (which was set in __project_get_revision()).
|
# Ignore current PROJECT_VER (which was set in project.cmake)
|
||||||
# Gets the version from the CONFIG_APP_PROJECT_VER.
|
# Gets the version from the CONFIG_APP_PROJECT_VER.
|
||||||
idf_build_set_property(PROJECT_VER "${CONFIG_APP_PROJECT_VER}")
|
idf_build_set_property(PROJECT_VER "${CONFIG_APP_PROJECT_VER}")
|
||||||
endif()
|
endif()
|
||||||
|
@ -361,6 +361,7 @@ The following are some project/build variables that are available as build prope
|
|||||||
* If :ref:`CONFIG_APP_PROJECT_VER_FROM_CONFIG` option is set, the value of :ref:`CONFIG_APP_PROJECT_VER` will be used.
|
* If :ref:`CONFIG_APP_PROJECT_VER_FROM_CONFIG` option is set, the value of :ref:`CONFIG_APP_PROJECT_VER` will be used.
|
||||||
* Else, if ``PROJECT_VER`` variable is set in project CMakeLists.txt file, its value will be used.
|
* Else, if ``PROJECT_VER`` variable is set in project CMakeLists.txt file, its value will be used.
|
||||||
* Else, if the ``PROJECT_DIR/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
|
* Else, if the ``PROJECT_DIR/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
|
||||||
|
* Else, if ``VERSION`` argument is passed to the ``project()`` call in the CMakeLists.txt file as ``project(... VERSION x.y.z.w )`` then it will be used as ``PROJECT_VER``. The ``VERSION`` argument must be compilant with the `cmake standard <https://cmake.org/cmake/help/v3.16/command/project.html>`_.
|
||||||
* Else, if the project is located inside a Git repository, the output of git description will be used.
|
* Else, if the project is located inside a Git repository, the output of git description will be used.
|
||||||
* Otherwise, ``PROJECT_VER`` will be "1".
|
* Otherwise, ``PROJECT_VER`` will be "1".
|
||||||
- ``EXTRA_PARTITION_SUBTYPES``: CMake list of extra partition subtypes. Each subtype description is a comma-separated string with ``type_name, subtype_name, numeric_value`` format. Components may add new subtypes by appending them to this list.
|
- ``EXTRA_PARTITION_SUBTYPES``: CMake list of extra partition subtypes. Each subtype description is a comma-separated string with ``type_name, subtype_name, numeric_value`` format. Components may add new subtypes by appending them to this list.
|
||||||
|
@ -361,6 +361,7 @@ ESP-IDF 在搜索所有待构建的组件时,会按照 ``COMPONENT_DIRS`` 指
|
|||||||
* 如果设置 :ref:`CONFIG_APP_PROJECT_VER_FROM_CONFIG` 选项,将会使用 :ref:`CONFIG_APP_PROJECT_VER` 的值。
|
* 如果设置 :ref:`CONFIG_APP_PROJECT_VER_FROM_CONFIG` 选项,将会使用 :ref:`CONFIG_APP_PROJECT_VER` 的值。
|
||||||
* 或者,如果在项目 CMakeLists.txt 文件中设置了 ``PROJECT_VER`` 变量,则该变量值可以使用。
|
* 或者,如果在项目 CMakeLists.txt 文件中设置了 ``PROJECT_VER`` 变量,则该变量值可以使用。
|
||||||
* 或者,如果 ``PROJECT_DIR/version.txt`` 文件存在,其内容会用作 ``PROJECT_VER`` 的值。
|
* 或者,如果 ``PROJECT_DIR/version.txt`` 文件存在,其内容会用作 ``PROJECT_VER`` 的值。
|
||||||
|
* 或者,如果在 CMakeLists.txt 文件中将 ``VERSION`` 参数传递给 ``project()`` 调用,形式为 ``project(... VERSION x.y.z.w )``,那么 ``VERSION`` 参数将用作为 ``PROJECT_VER`` 的值。``VERSION`` 参数必须符合 `cmake 标准 <https://cmake.org/cmake/help/v3.16/command/project.html>`_。
|
||||||
* 或者,如果项目位于某个 Git 仓库中,则使用 ``git describe`` 命令的输出作为 ``PROJECT_VER`` 的值。
|
* 或者,如果项目位于某个 Git 仓库中,则使用 ``git describe`` 命令的输出作为 ``PROJECT_VER`` 的值。
|
||||||
* 否则,``PROJECT_VER`` 的值为 1。
|
* 否则,``PROJECT_VER`` 的值为 1。
|
||||||
- ``EXTRA_PARTITION_SUBTYPES``:CMake 列表,用于创建额外的分区子类型。子类型的描述由字符串组成,以逗号为分隔,格式为 ``type_name, subtype_name, numeric_value``。组件可通过此列表,添加新的子类型。
|
- ``EXTRA_PARTITION_SUBTYPES``:CMake 列表,用于创建额外的分区子类型。子类型的描述由字符串组成,以逗号为分隔,格式为 ``type_name, subtype_name, numeric_value``。组件可通过此列表,添加新的子类型。
|
||||||
|
@ -64,30 +64,88 @@ endif()
|
|||||||
idf_build_set_property(__COMPONENT_MANAGER_INTERFACE_VERSION 2)
|
idf_build_set_property(__COMPONENT_MANAGER_INTERFACE_VERSION 2)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get the project version from either a version file or the Git revision. This is passed
|
# Parse and store the VERSION argument provided to the project() command.
|
||||||
# to the idf_build_process call. Dependencies are also set here for when the version file
|
|
||||||
# changes (if it is used).
|
|
||||||
#
|
#
|
||||||
function(__project_get_revision var)
|
function(__parse_and_store_version_arg)
|
||||||
|
# The project_name is the fisrt argument that was passed to the project() command
|
||||||
|
set(project_name ${ARGV0})
|
||||||
|
|
||||||
|
# Parse other arguments passed to the project() call
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs VERSION)
|
||||||
|
set(multiValueArgs)
|
||||||
|
cmake_parse_arguments(PROJECT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
# If the VERSION keyword exists but no version string is provided then raise a warning
|
||||||
|
if((NOT PROJECT_VERSION
|
||||||
|
OR PROJECT_VERSION STREQUAL "NOTFOUND")
|
||||||
|
AND NOT PROJECT_VERSION STREQUAL "0")
|
||||||
|
message(STATUS "VERSION keyword not followed by a value or was followed by a value that expanded to nothing.")
|
||||||
|
# Default the version to 1 in this case
|
||||||
|
set(project_ver 1)
|
||||||
|
else()
|
||||||
|
# Check if version is valid. cmake allows the version to be in the format <major>[.<minor>[.<patch>[.<tweak>]]]]
|
||||||
|
string(REGEX MATCH "^([0-9]+(\\.[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)?)?$" version_valid ${PROJECT_VERSION})
|
||||||
|
if(NOT version_valid AND NOT PROJECT_VERSION STREQUAL "0")
|
||||||
|
message(SEND_ERROR "Version \"${PROJECT_VERSION}\" format invalid.")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Split the version string into major, minor, patch, and tweak components
|
||||||
|
string(REPLACE "." ";" version_components ${PROJECT_VERSION})
|
||||||
|
list(GET version_components 0 PROJECT_VERSION_MAJOR)
|
||||||
|
list(LENGTH version_components version_length)
|
||||||
|
if(version_length GREATER 1)
|
||||||
|
list(GET version_components 1 PROJECT_VERSION_MINOR)
|
||||||
|
endif()
|
||||||
|
if(version_length GREATER 2)
|
||||||
|
list(GET version_components 2 PROJECT_VERSION_PATCH)
|
||||||
|
endif()
|
||||||
|
if(version_length GREATER 3)
|
||||||
|
list(GET version_components 3 PROJECT_VERSION_TWEAK)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Store the version string in cmake specified variables to access the version
|
||||||
|
set(PROJECT_VERSION ${PROJECT_VERSION} PARENT_SCOPE)
|
||||||
|
set(PROJECT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} PARENT_SCOPE)
|
||||||
|
if(PROJECT_VERSION_MINOR)
|
||||||
|
set(PROJECT_VERSION_MINOR ${PROJECT_VERSION_MINOR} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
if(PROJECT_VERSION_PATCH)
|
||||||
|
set(PROJECT_VERSION_PATCH ${PROJECT_VERSION_PATCH} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
if(PROJECT_VERSION_TWEAK)
|
||||||
|
set(PROJECT_VERSION_TWEAK ${PROJECT_VERSION_TWEAK} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Also store the version string in the specified variables for the project_name
|
||||||
|
set(${project_name}_VERSION ${PROJECT_VERSION} PARENT_SCOPE)
|
||||||
|
set(${project_name}_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} PARENT_SCOPE)
|
||||||
|
if(PROJECT_VERSION_MINOR)
|
||||||
|
set(${project_name}_VERSION_MINOR ${PROJECT_VERSION_MINOR} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
if(PROJECT_VERSION_PATCH)
|
||||||
|
set(${project_name}_VERSION_PATCH ${PROJECT_VERSION_PATCH} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
if(PROJECT_VERSION_TWEAK)
|
||||||
|
set(${project_name}_VERSION_TWEAK ${PROJECT_VERSION_TWEAK} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the project version from a version file. This is passed to the idf_build_process call.
|
||||||
|
# Dependencies are also set here for when the version file changes (if it is used).
|
||||||
|
#
|
||||||
|
function(__project_get_revision_from_version_file var)
|
||||||
set(_project_path "${CMAKE_CURRENT_LIST_DIR}")
|
set(_project_path "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
if(NOT DEFINED PROJECT_VER)
|
|
||||||
if(EXISTS "${_project_path}/version.txt")
|
if(EXISTS "${_project_path}/version.txt")
|
||||||
file(STRINGS "${_project_path}/version.txt" PROJECT_VER)
|
file(STRINGS "${_project_path}/version.txt" PROJECT_VER)
|
||||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_project_path}/version.txt")
|
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_project_path}/version.txt")
|
||||||
else()
|
|
||||||
git_describe(PROJECT_VER_GIT "${_project_path}")
|
|
||||||
if(PROJECT_VER_GIT)
|
|
||||||
set(PROJECT_VER ${PROJECT_VER_GIT})
|
|
||||||
else()
|
|
||||||
message(STATUS "Could not use 'git describe' to determine PROJECT_VER.")
|
|
||||||
set(PROJECT_VER 1)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
set(${var} "${PROJECT_VER}" PARENT_SCOPE)
|
set(${var} "${PROJECT_VER}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
# paths_with_spaces_to_list
|
# paths_with_spaces_to_list
|
||||||
#
|
#
|
||||||
# Replacement for spaces2list in cases where it was previously used on
|
# Replacement for spaces2list in cases where it was previously used on
|
||||||
@ -598,7 +656,54 @@ macro(project project_name)
|
|||||||
set(build_dir ${CMAKE_BINARY_DIR})
|
set(build_dir ${CMAKE_BINARY_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
__project_get_revision(project_ver)
|
# If PROJECT_VER has not been set yet, look for the version from various sources in the following order of priority:
|
||||||
|
#
|
||||||
|
# 1. version.txt file in the top level project directory
|
||||||
|
# 2. From the VERSION argument if passed to the project() macro
|
||||||
|
# 3. git describe if the project is in a git repository
|
||||||
|
# 4. Default to 1 if none of the above conditions are true
|
||||||
|
#
|
||||||
|
# PS: PROJECT_VER will get overidden later if CONFIG_APP_PROJECT_VER_FROM_CONFIG is defined.
|
||||||
|
# See components/esp_app_format/CMakeLists.txt.
|
||||||
|
if(NOT DEFINED PROJECT_VER)
|
||||||
|
# Read the version information from the version.txt file if it is present
|
||||||
|
__project_get_revision_from_version_file(project_ver)
|
||||||
|
|
||||||
|
# If the version is not set from the version.txt file, check other sources for the version information
|
||||||
|
if(NOT project_ver)
|
||||||
|
# Check if version information was passed to project() via the VERSION argument
|
||||||
|
set(version_keyword_present FALSE)
|
||||||
|
foreach(arg ${ARGN})
|
||||||
|
if(${arg} STREQUAL "VERSION")
|
||||||
|
set(version_keyword_present TRUE)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(version_keyword_present)
|
||||||
|
__parse_and_store_version_arg(${project_name} ${ARGN})
|
||||||
|
set(project_ver ${PROJECT_VERSION})
|
||||||
|
|
||||||
|
# If the project() command is called from the top-level CMakeLists.txt,
|
||||||
|
# store the version in CMAKE_PROJECT_VERSION.
|
||||||
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
|
set(CMAKE_PROJECT_VERSION ${PROJECT_VERSION})
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# Use git describe to determine the version
|
||||||
|
git_describe(PROJECT_VER_GIT "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
|
if(PROJECT_VER_GIT)
|
||||||
|
set(project_ver ${PROJECT_VER_GIT})
|
||||||
|
else()
|
||||||
|
message(STATUS "Could not use 'git describe' to determine PROJECT_VER.")
|
||||||
|
# None of sources contain the version information. Default PROJECT_VER to 1.
|
||||||
|
set(project_ver 1)
|
||||||
|
endif() #if(PROJECT_VER_GIT)
|
||||||
|
endif() #if(version_keyword_present)
|
||||||
|
endif() #if(NOT project_ver)
|
||||||
|
else()
|
||||||
|
# PROJECT_VER has been set before calling project(). Copy it into project_ver for idf_build_process() later.
|
||||||
|
set(project_ver ${PROJECT_VER})
|
||||||
|
endif() #if(NOT DEFINED PROJECT_VER)
|
||||||
|
|
||||||
message(STATUS "Building ESP-IDF components for target ${IDF_TARGET}")
|
message(STATUS "Building ESP-IDF components for target ${IDF_TARGET}")
|
||||||
|
|
||||||
|
@ -38,21 +38,44 @@ def pytest_addoption(parser: pytest.Parser) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name='session_work_dir', scope='session', autouse=True)
|
@pytest.fixture(scope='session')
|
||||||
def fixture_session_work_dir(request: FixtureRequest) -> typing.Generator[Path, None, None]:
|
def _session_work_dir(request: FixtureRequest) -> typing.Generator[typing.Tuple[Path, bool], None, None]:
|
||||||
work_dir = request.config.getoption('--work-dir')
|
work_dir = request.config.getoption('--work-dir')
|
||||||
|
|
||||||
if work_dir:
|
if work_dir:
|
||||||
work_dir = os.path.join(work_dir, datetime.datetime.utcnow().strftime('%Y-%m-%d_%H-%M-%S'))
|
work_dir = os.path.join(work_dir, datetime.datetime.utcnow().strftime('%Y-%m-%d_%H-%M-%S'))
|
||||||
logging.debug(f'using work directory: {work_dir}')
|
logging.debug(f'using work directory: {work_dir}')
|
||||||
os.makedirs(work_dir, exist_ok=True)
|
os.makedirs(work_dir, exist_ok=True)
|
||||||
clean_dir = None
|
clean_dir = None
|
||||||
|
is_temp_dir = False
|
||||||
else:
|
else:
|
||||||
work_dir = mkdtemp()
|
work_dir = mkdtemp()
|
||||||
logging.debug(f'created temporary work directory: {work_dir}')
|
logging.debug(f'created temporary work directory: {work_dir}')
|
||||||
clean_dir = work_dir
|
clean_dir = work_dir
|
||||||
|
is_temp_dir = True
|
||||||
|
|
||||||
# resolve allows to use relative paths with --work-dir option
|
# resolve allows using relative paths with --work-dir option
|
||||||
yield Path(work_dir).resolve()
|
yield Path(work_dir).resolve(), is_temp_dir
|
||||||
|
|
||||||
|
if clean_dir:
|
||||||
|
logging.debug(f'cleaning up {clean_dir}')
|
||||||
|
shutil.rmtree(clean_dir, ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name='func_work_dir', autouse=True)
|
||||||
|
def work_dir(request: FixtureRequest, _session_work_dir: typing.Tuple[Path, bool]) -> typing.Generator[Path, None, None]:
|
||||||
|
session_work_dir, is_temp_dir = _session_work_dir
|
||||||
|
|
||||||
|
if request._pyfuncitem.keywords.get('force_temp_work_dir') and not is_temp_dir:
|
||||||
|
work_dir = Path(mkdtemp()).resolve()
|
||||||
|
logging.debug('Force using temporary work directory')
|
||||||
|
clean_dir = work_dir
|
||||||
|
else:
|
||||||
|
work_dir = session_work_dir
|
||||||
|
clean_dir = None
|
||||||
|
|
||||||
|
# resolve allows using relative paths with --work-dir option
|
||||||
|
yield work_dir
|
||||||
|
|
||||||
if clean_dir:
|
if clean_dir:
|
||||||
logging.debug(f'cleaning up {clean_dir}')
|
logging.debug(f'cleaning up {clean_dir}')
|
||||||
@ -60,7 +83,7 @@ def fixture_session_work_dir(request: FixtureRequest) -> typing.Generator[Path,
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_app_copy(session_work_dir: Path, request: FixtureRequest) -> typing.Generator[Path, None, None]:
|
def test_app_copy(func_work_dir: Path, request: FixtureRequest) -> typing.Generator[Path, None, None]:
|
||||||
# by default, use hello_world app and copy it to a temporary directory with
|
# by default, use hello_world app and copy it to a temporary directory with
|
||||||
# the name resembling that of the test
|
# the name resembling that of the test
|
||||||
copy_from = 'tools/test_build_system/build_test_app'
|
copy_from = 'tools/test_build_system/build_test_app'
|
||||||
@ -74,7 +97,7 @@ def test_app_copy(session_work_dir: Path, request: FixtureRequest) -> typing.Gen
|
|||||||
copy_to = mark.args[1]
|
copy_to = mark.args[1]
|
||||||
|
|
||||||
path_from = Path(os.environ['IDF_PATH']) / copy_from
|
path_from = Path(os.environ['IDF_PATH']) / copy_from
|
||||||
path_to = session_work_dir / copy_to
|
path_to = func_work_dir / copy_to
|
||||||
|
|
||||||
# if the new directory inside the original directory,
|
# if the new directory inside the original directory,
|
||||||
# make sure not to go into recursion.
|
# make sure not to go into recursion.
|
||||||
@ -99,13 +122,13 @@ def test_app_copy(session_work_dir: Path, request: FixtureRequest) -> typing.Gen
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_git_template_app(session_work_dir: Path, request: FixtureRequest) -> typing.Generator[Path, None, None]:
|
def test_git_template_app(func_work_dir: Path, request: FixtureRequest) -> typing.Generator[Path, None, None]:
|
||||||
copy_to = request.node.name + '_app'
|
copy_to = request.node.name + '_app'
|
||||||
path_to = session_work_dir / copy_to
|
path_to = func_work_dir / copy_to
|
||||||
|
|
||||||
logging.debug(f'clonning git-teplate app to {path_to}')
|
logging.debug(f'cloning git-template app to {path_to}')
|
||||||
path_to.mkdir()
|
path_to.mkdir()
|
||||||
# No need to clone full repository, just single master branch
|
# No need to clone full repository, just a single master branch
|
||||||
subprocess.run(['git', 'clone', '--single-branch', '-b', 'master', '--depth', '1', 'https://github.com/espressif/esp-idf-template.git', '.'],
|
subprocess.run(['git', 'clone', '--single-branch', '-b', 'master', '--depth', '1', 'https://github.com/espressif/esp-idf-template.git', '.'],
|
||||||
cwd=path_to, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
cwd=path_to, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
@ -122,7 +145,7 @@ def test_git_template_app(session_work_dir: Path, request: FixtureRequest) -> ty
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def idf_copy(session_work_dir: Path, request: FixtureRequest) -> typing.Generator[Path, None, None]:
|
def idf_copy(func_work_dir: Path, request: FixtureRequest) -> typing.Generator[Path, None, None]:
|
||||||
copy_to = request.node.name + '_idf'
|
copy_to = request.node.name + '_idf'
|
||||||
|
|
||||||
# allow overriding the destination via pytest.mark.idf_copy()
|
# allow overriding the destination via pytest.mark.idf_copy()
|
||||||
@ -131,7 +154,7 @@ def idf_copy(session_work_dir: Path, request: FixtureRequest) -> typing.Generato
|
|||||||
copy_to = mark.args[0]
|
copy_to = mark.args[0]
|
||||||
|
|
||||||
path_from = EXT_IDF_PATH
|
path_from = EXT_IDF_PATH
|
||||||
path_to = session_work_dir / copy_to
|
path_to = func_work_dir / copy_to
|
||||||
|
|
||||||
# if the new directory inside the original directory,
|
# if the new directory inside the original directory,
|
||||||
# make sure not to go into recursion.
|
# make sure not to go into recursion.
|
||||||
|
@ -16,3 +16,4 @@ junit_log_passing_tests = False
|
|||||||
markers =
|
markers =
|
||||||
test_app_copy: specify relative path of the app to copy, and the prefix of the destination directory name
|
test_app_copy: specify relative path of the app to copy, and the prefix of the destination directory name
|
||||||
idf_copy: specify the prefix of the destination directory where IDF should be copied
|
idf_copy: specify the prefix of the destination directory where IDF should be copied
|
||||||
|
force_temp_work_dir: force temporary folder as the working directory
|
||||||
|
@ -19,9 +19,9 @@ def assert_built(paths: Union[List[str], List[Path]]) -> None:
|
|||||||
assert os.path.exists(path)
|
assert os.path.exists(path)
|
||||||
|
|
||||||
|
|
||||||
def test_build_alternative_directories(idf_py: IdfPyFunc, session_work_dir: Path, test_app_copy: Path) -> None:
|
def test_build_alternative_directories(idf_py: IdfPyFunc, func_work_dir: Path, test_app_copy: Path) -> None:
|
||||||
logging.info('Moving BUILD_DIR_BASE out of tree')
|
logging.info('Moving BUILD_DIR_BASE out of tree')
|
||||||
alt_build_dir = session_work_dir / 'alt_build'
|
alt_build_dir = func_work_dir / 'alt_build'
|
||||||
idf_py('-B', str(alt_build_dir), 'build')
|
idf_py('-B', str(alt_build_dir), 'build')
|
||||||
assert os.listdir(alt_build_dir) != [], 'No files found in new build directory!'
|
assert os.listdir(alt_build_dir) != [], 'No files found in new build directory!'
|
||||||
default_build_dir = test_app_copy / 'build'
|
default_build_dir = test_app_copy / 'build'
|
||||||
|
@ -8,7 +8,7 @@ import subprocess
|
|||||||
import typing
|
import typing
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from test_build_system_helpers import EnvDict, IdfPyFunc, run_idf_py
|
from test_build_system_helpers import EnvDict, run_idf_py
|
||||||
|
|
||||||
|
|
||||||
def run_git_cmd(*args: str,
|
def run_git_cmd(*args: str,
|
||||||
@ -25,13 +25,6 @@ def run_git_cmd(*args: str,
|
|||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
|
|
||||||
def test_get_version_from_git_describe(test_git_template_app: Path, idf_py: IdfPyFunc) -> None:
|
|
||||||
logging.info('Get the version of app from git describe. Project is not inside IDF and do not have a tag only a hash commit.')
|
|
||||||
idf_ret = idf_py('reconfigure')
|
|
||||||
git_ret = run_git_cmd('describe', '--always', '--tags', '--dirty', workdir=test_git_template_app)
|
|
||||||
assert f'App "app-template" version: {git_ret.stdout.decode("utf-8")}' in idf_ret.stdout, 'Project version should have a hash commit'
|
|
||||||
|
|
||||||
|
|
||||||
# In this test, the action needs to be performed in ESP-IDF that is valid git directory
|
# In this test, the action needs to be performed in ESP-IDF that is valid git directory
|
||||||
# Copying ESP-IDF is not possible
|
# Copying ESP-IDF is not possible
|
||||||
def test_git_custom_tag() -> None:
|
def test_git_custom_tag() -> None:
|
||||||
|
@ -124,12 +124,3 @@ def test_kconfig_multiple_and_target_specific_options(idf_py: IdfPyFunc, test_ap
|
|||||||
idf_py('set-target', 'esp32s2')
|
idf_py('set-target', 'esp32s2')
|
||||||
assert all([file_contains((test_app_copy / 'sdkconfig'), x) for x in ['CONFIG_TEST_NEW_OPTION=y',
|
assert all([file_contains((test_app_copy / 'sdkconfig'), x) for x in ['CONFIG_TEST_NEW_OPTION=y',
|
||||||
'CONFIG_TEST_OLD_OPTION=y']])
|
'CONFIG_TEST_OLD_OPTION=y']])
|
||||||
|
|
||||||
|
|
||||||
def test_kconfig_get_version_from_describe(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
|
||||||
logging.info('Get the version of app from Kconfig option')
|
|
||||||
(test_app_copy / 'version.txt').write_text('project_version_from_txt')
|
|
||||||
(test_app_copy / 'sdkconfig.defaults').write_text('\n'.join(['CONFIG_APP_PROJECT_VER_FROM_CONFIG=y',
|
|
||||||
'CONFIG_APP_PROJECT_VER="project_version_from_Kconfig"']))
|
|
||||||
ret = idf_py('build')
|
|
||||||
assert 'App "build_test_app" version: project_version_from_Kconfig' in ret.stdout
|
|
||||||
|
182
tools/test_build_system/test_versions.py
Normal file
182
tools/test_build_system/test_versions.py
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import typing
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from test_build_system_helpers import EnvDict, IdfPyFunc, append_to_file, replace_in_file
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################################
|
||||||
|
# Test Case: Test that the build-system can set the default version for an IDF app
|
||||||
|
#
|
||||||
|
# Test Steps:
|
||||||
|
# 1. Copy the base build_test_app
|
||||||
|
# 2. Run idf.py reconfigure
|
||||||
|
# 3. Verify that the app version takes the default value of 1
|
||||||
|
#
|
||||||
|
# Note: This test must run outside a git repository for it to pass. Hence we force the test
|
||||||
|
# to use a temporary work directory.
|
||||||
|
#############################################################################################
|
||||||
|
@pytest.mark.force_temp_work_dir
|
||||||
|
def test_versions_get_default_version(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||||
|
logging.info('Verify the default version of an app')
|
||||||
|
ret = idf_py('reconfigure')
|
||||||
|
assert 'App "build_test_app" version: 1' in ret.stdout
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################################
|
||||||
|
# Test Case: Test that the build-system can set the version of an IDF app from git describe
|
||||||
|
#
|
||||||
|
# Test Steps:
|
||||||
|
# 1. Clone the idf template app from https://github.com/espressif/esp-idf-template.git
|
||||||
|
# 2. Run idf.py reconfigure
|
||||||
|
# 3. Run git describe in the cloned app git repository
|
||||||
|
# 4. Verify that the app version is picked up from the git describe command
|
||||||
|
#
|
||||||
|
#############################################################################################
|
||||||
|
def test_versions_get_version_from_git_describe(idf_py: IdfPyFunc,
|
||||||
|
test_git_template_app: Path,
|
||||||
|
env: typing.Optional[EnvDict] = None) -> None:
|
||||||
|
logging.info('Verify that the version of app can be set from git describe')
|
||||||
|
idf_ret = idf_py('reconfigure')
|
||||||
|
env_dict = dict(**os.environ)
|
||||||
|
if env:
|
||||||
|
env_dict.update(env)
|
||||||
|
git_ret = subprocess.run(['git', 'describe', '--always', '--tags', '--dirty'],
|
||||||
|
cwd=test_git_template_app, env=env_dict, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
assert f'App "app-template" version: {git_ret.stdout.decode("utf-8")}' in idf_ret.stdout
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################################
|
||||||
|
# Test Case: Test that the build-system can set the version for an IDF app from the VERSION argument
|
||||||
|
#
|
||||||
|
# Test Steps:
|
||||||
|
# 1. Clone the idf template app from https://github.com/espressif/esp-idf-template.git
|
||||||
|
# 2. Replace the default project() command in the top level CMakeLists.txt file to call the version parsing
|
||||||
|
# function __parse_and_store_version_arg()
|
||||||
|
# 3. Append several calls to __parse_and_store_version_arg() with different inputs for the VERSION argument
|
||||||
|
# 4. Append a project() call with valid arguments at the end of the CMakeLists.txt file
|
||||||
|
# 5. Run idf.py reconfigure
|
||||||
|
# 6. Verify that cmake correctly flags invalid inputs for the VERSION argument and accepts valid inputs for the same
|
||||||
|
#
|
||||||
|
#############################################################################################
|
||||||
|
def test_versions_get_version_from_version_arg(idf_py: IdfPyFunc, test_git_template_app: Path) -> None:
|
||||||
|
logging.info('Verify that the VERSION argument in project() is correctly parsed by cmake')
|
||||||
|
|
||||||
|
# empty VERSION argument
|
||||||
|
replace_in_file((test_git_template_app / 'CMakeLists.txt'), 'project(app-template)',
|
||||||
|
'__parse_and_store_version_arg(app-template VERSION)')
|
||||||
|
# Invalid VERSION argument format
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'),
|
||||||
|
'\n__parse_and_store_version_arg(app-tempplate VERSION 1..2)')
|
||||||
|
# Invalid VERSION argument format
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'),
|
||||||
|
'\n__parse_and_store_version_arg(app-template VERSION version_text)')
|
||||||
|
# Invalid VERSION argument format
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'),
|
||||||
|
'\n__parse_and_store_version_arg(app-template VERSION 1.2.3.4.5)')
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'),
|
||||||
|
'\n__parse_and_store_version_arg(app-template VERSION 0)')
|
||||||
|
# Valid VERSION argument format
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'),
|
||||||
|
'\n__parse_and_store_version_arg(app-template VERSION 0.1)')
|
||||||
|
# Valid VERSION argument format
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'),
|
||||||
|
'\n__parse_and_store_version_arg(app-template VERSION 0.1.2)')
|
||||||
|
# Valid VERSION argument format
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'),
|
||||||
|
'\n__parse_and_store_version_arg(app-template VERSION 0.1.2.3)')
|
||||||
|
# project() call with valid VERSION argument format
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'),
|
||||||
|
'\nproject(app-template VERSION 0.1.2.3)')
|
||||||
|
|
||||||
|
with pytest.raises(subprocess.CalledProcessError) as e:
|
||||||
|
idf_py('reconfigure')
|
||||||
|
|
||||||
|
assert 'VERSION keyword not followed by a value or was followed by a value that expanded to nothing.' in e.stdout
|
||||||
|
assert 'Version "1..2" format invalid' in e.stderr
|
||||||
|
assert 'Version "version_text" format invalid' in e.stderr
|
||||||
|
assert 'Version "1.2.3.4.5" format invalid' in e.stderr
|
||||||
|
assert 'Version "1.2.3.4.5" format invalid' in e.stderr
|
||||||
|
assert 'Version "0" format invalid' not in e.stderr
|
||||||
|
assert 'Version "0.1" format invalid' not in e.stderr
|
||||||
|
assert 'Version "0.1.2" format invalid' not in e.stderr
|
||||||
|
assert 'Version "0.1.2.3" format invalid' not in e.stderr
|
||||||
|
assert 'App "app-template" version: 0.1.2.3' in e.stdout
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################################
|
||||||
|
# Test Case: Test that the build-system can set the version of an IDF app from version.txt file
|
||||||
|
#
|
||||||
|
# Test Steps:
|
||||||
|
# 1. Clone the idf template app from https://github.com/espressif/esp-idf-template.git
|
||||||
|
# 2. Replace the default project() command in the top level CMakeLists.txt file to include VERSION argument
|
||||||
|
# 3. Copy version.txt file into the cloned app repository
|
||||||
|
# 4. Updated the version in version.txt file to a known value
|
||||||
|
# 5. Run idf.py reconfigure
|
||||||
|
# 6. Verify that the app version is picked up from the version.txt file
|
||||||
|
#
|
||||||
|
#############################################################################################
|
||||||
|
def test_versions_get_version_from_version_file(idf_py: IdfPyFunc, test_git_template_app: Path) -> None:
|
||||||
|
logging.info('Verify that the version of app can be set from version.txt file')
|
||||||
|
replace_in_file((test_git_template_app / 'CMakeLists.txt'), 'project(app-template)',
|
||||||
|
'project(app-template VERSION 0.1.2.3)')
|
||||||
|
(test_git_template_app / 'version.txt').write_text('project_version_from_txt')
|
||||||
|
idf_ret = idf_py('reconfigure')
|
||||||
|
|
||||||
|
assert f'App "app-template" version: project_version_from_txt' in idf_ret.stdout
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################################
|
||||||
|
# Test Case: Test that the build-system can set the version of an IDF app if PROJECT_VER is set in the CMakeLists.txt
|
||||||
|
#
|
||||||
|
# Test Steps:
|
||||||
|
# 1. Clone the idf template app from https://github.com/espressif/esp-idf-template.git
|
||||||
|
# 2. Update CMakeLists.txt file to set PROJECT_VER before calling project()
|
||||||
|
# 3. Replace the default project() command in the top level CMakeLists.txt file to include VERSION argument
|
||||||
|
# 4. Copy version.txt file into the cloned app repository
|
||||||
|
# 5. Updated the version in version.txt file to a known value
|
||||||
|
# 6. Run idf.py reconfigure
|
||||||
|
# 7. Verify that the app version is picked up from the CMakeLists.txt file
|
||||||
|
#
|
||||||
|
#############################################################################################
|
||||||
|
def test_versions_get_version_from_top_level_cmake(idf_py: IdfPyFunc, test_git_template_app: Path) -> None:
|
||||||
|
logging.info('Verify that the version of app can be set from PROJECT_VER in CMakeLists.txt')
|
||||||
|
replace_in_file((test_git_template_app / 'CMakeLists.txt'), 'project(app-template)',
|
||||||
|
'set(PROJECT_VER project_version_from_CMakeLists)')
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'), 'project(app-template VERSION 0.1.2.3)')
|
||||||
|
(test_git_template_app / 'version.txt').write_text('project_version_from_txt')
|
||||||
|
idf_ret = idf_py('reconfigure')
|
||||||
|
|
||||||
|
assert f'App "app-template" version: project_version_from_CMakeLists' in idf_ret.stdout
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################################
|
||||||
|
# Test Case: Test that the build-system can set the version of an IDF app from Kconfig option
|
||||||
|
#
|
||||||
|
# Test Steps:
|
||||||
|
# 1. Clone the idf template app from https://github.com/espressif/esp-idf-template.git
|
||||||
|
# 2. Update CMakeLists.txt file to set PROJECT_VER before calling project()
|
||||||
|
# 3. Replace the default project() command in the top level CMakeLists.txt file to include VERSION argument
|
||||||
|
# 4. Copy version.txt file into the cloned app repository
|
||||||
|
# 5. Updated the version in version.txt file to a known value
|
||||||
|
# 6. Run idf.py reconfigure
|
||||||
|
# 7. Updated sdkconfig.defaults to configure CONFIG_APP_PROJECT_VER_FROM_CONFIG and CONFIG_APP_PROJECT_VER
|
||||||
|
# 8. Run idf.py reconfigure
|
||||||
|
# 9. Verify that the app version is picked up from the Kconfig option
|
||||||
|
#
|
||||||
|
#############################################################################################
|
||||||
|
def test_versions_get_version_from_kconfig_option(idf_py: IdfPyFunc, test_git_template_app: Path) -> None:
|
||||||
|
logging.info('Verify that the version of app can be set from Kconfig option')
|
||||||
|
replace_in_file((test_git_template_app / 'CMakeLists.txt'), 'project(app-template)',
|
||||||
|
'set(PROJECT_VER project_version_from_CMakeLists)')
|
||||||
|
append_to_file((test_git_template_app / 'CMakeLists.txt'), 'project(app-template VERSION 0.1.2.3)')
|
||||||
|
(test_git_template_app / 'sdkconfig.defaults').write_text('\n'.join(['CONFIG_APP_PROJECT_VER_FROM_CONFIG=y',
|
||||||
|
'CONFIG_APP_PROJECT_VER="project_version_from_Kconfig"']))
|
||||||
|
idf_ret = idf_py('reconfigure')
|
||||||
|
|
||||||
|
assert f'App "app-template" version: project_version_from_Kconfig' in idf_ret.stdout
|
Loading…
Reference in New Issue
Block a user