From 96e197b4ece6ad8e614d9459f047b114583fbfdb Mon Sep 17 00:00:00 2001 From: Eddy Ashton Date: Thu, 29 Apr 2021 12:04:35 +0100 Subject: [PATCH] Change install prefix and cmake version parsing (#2530) --- .azure-pipelines-templates/install.yml | 4 +- CHANGELOG.md | 7 +++ CMakeLists.txt | 11 ++-- cmake/cpack_settings.cmake | 9 ++++ cmake/version.cmake | 66 +++++++++++++++-------- python/setup.py.in | 3 +- python/versionifier.py | 73 ++++++++++++++++++++++++++ 7 files changed, 145 insertions(+), 28 deletions(-) create mode 100644 python/versionifier.py diff --git a/.azure-pipelines-templates/install.yml b/.azure-pipelines-templates/install.yml index d8c89330f3..816a8a0ad9 100644 --- a/.azure-pipelines-templates/install.yml +++ b/.azure-pipelines-templates/install.yml @@ -25,7 +25,9 @@ steps: - script: | set -ex - CCF_VERSION=$(<../../build/VERSION) + CCF_VERSION=$(<../../build/VERSION_LONG) + CCF_VERSION=${CCF_VERSION#ccf-} + echo "Setting npm package version to ${CCF_VERSION}" npm version $CCF_VERSION npm pack PKG=`ls *.tgz` diff --git a/CHANGELOG.md b/CHANGELOG.md index dcd8448f96..3c936a5543 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.0.0-rc1] + +### Changed + +- By default, CCF is now installed under `/opt/ccf` rather than `/opt/ccf-x.y.z`. + ## [0.99.4] ### Fixed @@ -823,6 +829,7 @@ Some discrepancies with the TR remain, and are being tracked under https://githu Initial pre-release +[1.0.0-rc1]: https://github.com/microsoft/CCF/releases/tag/ccf-1.0.0-rc1 [0.99.4]: https://github.com/microsoft/CCF/releases/tag/ccf-0.99.4 [0.99.3]: https://github.com/microsoft/CCF/releases/tag/ccf-0.99.3 [0.99.2]: https://github.com/microsoft/CCF/releases/tag/ccf-0.99.2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 258e51bd4e..9ab766df77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,9 @@ project( set(ENV{BETTER_EXCEPTIONS} 1) -message(STATUS "CCF version=${CCF_VERSION}") -message(STATUS "CCF release version=${CCF_RELEASE_VERSION}") +message(STATUS "CCF version = ${CCF_VERSION}") +message(STATUS "CCF release version = ${CCF_RELEASE_VERSION}") +message(STATUS "CCF version suffix = ${CCF_VERSION_SUFFIX}") include(${CCF_DIR}/cmake/cpack_settings.cmake) @@ -26,7 +27,7 @@ include(${CCF_DIR}/cmake/cpack_settings.cmake) # if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX - "/opt/${CCF_VERSION}" + "/opt/ccf" CACHE PATH "Default install prefix" FORCE ) endif() @@ -441,6 +442,10 @@ if(BUILD_TESTS) APPEND PROPERTY LABELS unit_test ) + + add_test(NAME versionifier_test + COMMAND ${PYTHON} ${CMAKE_SOURCE_DIR}/python/versionifier.py + ) endif() # Picobench benchmarks diff --git a/cmake/cpack_settings.cmake b/cmake/cpack_settings.cmake index 15aca33d3e..8c75164ac2 100644 --- a/cmake/cpack_settings.cmake +++ b/cmake/cpack_settings.cmake @@ -9,6 +9,15 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CCF_DIR}/LICENSE") set(CPACK_PACKAGE_VERSION ${CCF_RELEASE_VERSION}) set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) +if(CCF_VERSION_SUFFIX) + set(CPACK_DEBIAN_PACKAGE_VERSION + "${CCF_RELEASE_VERSION}~${CCF_VERSION_SUFFIX}" + ) + message( + STATUS "Debian package will include suffix: ${CPACK_DEBIAN_PACKAGE_VERSION}" + ) +endif() + # CPack variables for Debian packages set(CPACK_DEBIAN_PACKAGE_DEPENDS "open-enclave (>=0.15.0), libuv1 (>= 1.18.0), libc++1-8, libc++abi1-8" diff --git a/cmake/version.cmake b/cmake/version.cmake index e1e61181c7..be9c5c74b3 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -3,52 +3,69 @@ unset(CCF_VERSION) unset(CCF_RELEASE_VERSION) +unset(CCF_VERSION_SUFFIX) # If possible, deduce project version from git environment if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) find_package(Git) execute_process( - COMMAND "bash" "-c" "${GIT_EXECUTABLE} describe --tags | grep ccf-" + COMMAND "bash" "-c" "${GIT_EXECUTABLE} describe --tags" OUTPUT_VARIABLE "CCF_VERSION" OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE RETURN_CODE ) if(NOT RETURN_CODE STREQUAL "0") + message(FATAL_ERROR "Error calling git describe") + endif() + + # Convert git description into cmake list, separated at '-' + string(REPLACE "-" ";" CCF_VERSION_COMPONENTS ${CCF_VERSION}) + + # Check that the first element equals "ccf" + list(GET CCF_VERSION_COMPONENTS 0 FIRST) + if(NOT FIRST STREQUAL "ccf") message( FATAL_ERROR "Git repository does not appear to contain any tag starting with ccf- (the repository should be cloned with sufficient depth to access the latest \"ccf-*\" tag)" ) endif() - execute_process( - COMMAND "bash" "-c" - "${GIT_EXECUTABLE} describe --tags --abbrev=0 | tr -d ccf-" - OUTPUT_VARIABLE "CCF_RELEASE_VERSION" - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endif() - -if(NOT CCF_RELEASE_VERSION) +else() # If not in a git environment (e.g. release tarball), deduce version from the # source directory name execute_process( - COMMAND "bash" "-c" - "[[ $(basename ${CMAKE_CURRENT_SOURCE_DIR}) =~ ^CCF-.* ]]" - RESULT_VARIABLE "IS_CCF_FOLDER" - ) - - if(NOT ${IS_CCF_FOLDER} STREQUAL "0") - message(FATAL_ERROR "Sources directory is not in \"CCF-...\" folder") - endif() - - execute_process( - COMMAND "bash" "-c" "basename ${CMAKE_CURRENT_SOURCE_DIR} | cut -d'-' -f2" + COMMAND "bash" "-c" "basename ${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE "CCF_VERSION" OUTPUT_STRIP_TRAILING_WHITESPACE ) - set(CCF_RELEASE_VERSION ${CCF_VERSION}) - message(STATUS "CCF version deduced from sources directory: ${CCF_VERSION}") + # Convert directory name into cmake list, separated at '-' + string(REPLACE "-" ";" CCF_VERSION_COMPONENTS ${CCF_VERSION}) + + # Check that the first element equals "ccf" + list(GET CCF_VERSION_COMPONENTS 0 FIRST) + if(NOT FIRST STREQUAL "ccf") + message(FATAL_ERROR "Sources directory is not in \"ccf-...\" folder") + endif() + + message( + STATUS "Extracting CCF version from sources directory: ${CCF_VERSION}" + ) +endif() + +# Check that we have at least ccf-x.y.z +list(LENGTH CCF_VERSION_COMPONENTS CCF_VERSION_COMPONENTS_LENGTH) +if(NOT CCF_VERSION_COMPONENTS_LENGTH GREATER_EQUAL 2) + message(FATAL_ERROR "Version does not contain expected ccf-x.y.z") +endif() + +# Get the main version number +list(GET CCF_VERSION_COMPONENTS 1 CCF_RELEASE_VERSION) + +# If there is any suffix, store it +if(CCF_VERSION_COMPONENTS_LENGTH GREATER 2) + list(SUBLIST CCF_VERSION_COMPONENTS 2 -1 CCF_VERSION_SUFFIX) + list(JOIN CCF_VERSION_SUFFIX "-" CCF_VERSION_SUFFIX) endif() # Check that release version is semver @@ -68,3 +85,6 @@ endif() file(WRITE ${CMAKE_BINARY_DIR}/VERSION "${CCF_RELEASE_VERSION}") install(FILES ${CMAKE_BINARY_DIR}/VERSION DESTINATION share) + +file(WRITE ${CMAKE_BINARY_DIR}/VERSION_LONG "${CCF_VERSION}") +install(FILES ${CMAKE_BINARY_DIR}/VERSION_LONG DESTINATION share) diff --git a/python/setup.py.in b/python/setup.py.in index b4f74ec9b5..f0150c1242 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -3,6 +3,7 @@ from setuptools import setup # type: ignore from os import path +import versionifier PACKAGE_NAME = "ccf" UTILITIES_PATH = "utils" @@ -17,7 +18,7 @@ with open('requirements.txt') as f: setup( name=PACKAGE_NAME, - version="@CCF_RELEASE_VERSION@", + version=str(versionifier.to_python_version("@CCF_VERSION@")), description="Set of tools and utilities for the Confidential Consortium Framework (CCF)", long_description=long_description, long_description_content_type="text/markdown", diff --git a/python/versionifier.py b/python/versionifier.py new file mode 100644 index 0000000000..f6ca0920ff --- /dev/null +++ b/python/versionifier.py @@ -0,0 +1,73 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the Apache 2.0 License. + +# pylint: disable=import-error, no-name-in-module +from setuptools.extern.packaging.version import ( # type: ignore + Version, + InvalidVersion, +) + + +def remove_prefix(s, prefix): + if s.startswith(prefix): + return s[len(prefix) :] + return s + + +def replace_char(s, n, c): + return s[:n] + str(c) + s[n + 1 :] + + +def to_python_version(original): + unprefixed = remove_prefix(original, "ccf-") + + # Try to parse this as a Version (with automatic normalisation). + # If it fails, try making part of the suffix a local version specifier (+foo). + # Keep expanding this suffix until you get a valid version, or run out of attempts. + next_attempt = unprefixed + next_replace = len(next_attempt) + while True: + try: + version = Version(next_attempt) + return version + except InvalidVersion: + next_replace = unprefixed.rfind("-", 0, next_replace) + if next_replace == -1: + break + next_attempt = replace_char(unprefixed, next_replace, "+") + + raise ValueError(f"Cannot convert '{original}' to a Version") + + +if __name__ == "__main__": + # Run some tests that expected versions are correctly parsed + v = to_python_version("1") + assert v.release == (1,) + + v = to_python_version("1.2.3") + assert v.release == (1, 2, 3) + + v = to_python_version("ccf-1.2.3") + assert v.release == (1, 2, 3) + + v = to_python_version("ccf-1.2.3-a42") + assert v.release == (1, 2, 3) + assert v.pre == ("a", 42) + + v = to_python_version("ccf-1.2.3-rc1") + assert v.release == (1, 2, 3) + assert v.pre == ("rc", 1) + + v = to_python_version("ccf-1.2.3-dev2") + assert v.release == (1, 2, 3) + assert v.dev == 2 + + v = to_python_version("ccf-1.2.3-dev3-5-deadbeef") + assert v.release == (1, 2, 3) + assert v.dev == 3 + assert v.local == "5.deadbeef" + + v = to_python_version("ccf-1.2.3-42-deadbeef") + assert v.release == (1, 2, 3) + assert v.post == 42 + assert v.local == "deadbeef"