diff --git a/CMakeLists.txt b/CMakeLists.txt index 9634465311d1a2746bd88faba6f7c541c7d878c4..a26ab9fed86952ec1cb70f826fdbdec22ddfa35a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ # See LICENSE in the root of the software repository for the full text of the License. # ====================================================================================================================== -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.16) project (MetaDef[CXX]) # 存在`.dev_env`文件说明是蓝区开发环境,并且调用了`prepare_dev_env.sh`完成了开发环境准备 @@ -36,6 +36,15 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.dev_env") set(ASCEND_INSTALL_PATH ${ASCEND_INSTALL_PATH}/latest) endif() +set(OPEN_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../open_source") +if(NOT EXISTS ${OPEN_SOURCE_DIR}) + message(STATUS "Build with dependency communtiy cann pkgs installed") + option(BUILD_WITH_INSTALLED_DEPENDENCY_CANN_PKG_COMMUNITY "Build with dependency communtiy cann pkgs installed" TRUE) +else() + message(STATUS "Build with dependency communtiy cann pkgs not installed") + option(BUILD_WITH_INSTALLED_DEPENDENCY_CANN_PKG_COMMUNITY "Build with dependency communtiy cann pkgs not installed" FALSE) +endif() + if (NOT DEFINED CMAKE_MODULE_PATH OR NOT DEFINED CMAKE_PREFIX_PATH) # In a developer environment, neither CMAKE_MODULE_PATH nor CMAKE_PREFIX_PATH is set. if (NOT DEFINED ASCEND_INSTALL_PATH OR NOT DEFINED ASCEND_3RD_LIB_PATH) @@ -45,10 +54,16 @@ if (NOT DEFINED CMAKE_MODULE_PATH OR NOT DEFINED CMAKE_PREFIX_PATH) endif () if (NOT DEFINED CMAKE_MODULE_PATH) - set(CMAKE_MODULE_PATH - ${CMAKE_CURRENT_LIST_DIR}/cmake/modules - ${ASCEND_3RD_LIB_PATH}/cmake/modules - ) + if(BUILD_WITH_INSTALLED_DEPENDENCY_CANN_PKG_COMMUNITY) + set(CMAKE_MODULE_PATH + ${CMAKE_CURRENT_LIST_DIR}/cmake/modules + ${ASCEND_3RD_LIB_PATH}/cmake/modules + ) + else() + set(CMAKE_MODULE_PATH + ${CMAKE_CURRENT_LIST_DIR}/cmake/modules/sub_module + ) + endif() endif() if (NOT DEFINED CMAKE_PREFIX_PATH) @@ -98,11 +113,19 @@ if (ENABLE_OPEN_SRC) include(cmake/test_funcs.cmake) include(cmake/intf_pub_linux.cmake) - find_package(ascend_protobuf_shared MODULE REQUIRED) - find_package(ascend_protobuf_static MODULE REQUIRED) - find_package(protoc MODULE REQUIRED) - find_package(json MODULE REQUIRED) - find_package(GTest CONFIG REQUIRED) + if(BUILD_WITH_INSTALLED_DEPENDENCY_CANN_PKG_COMMUNITY) + find_package(ascend_protobuf_shared MODULE REQUIRED) + find_package(ascend_protobuf_static MODULE REQUIRED) + find_package(protoc MODULE REQUIRED) + find_package(json MODULE REQUIRED) + find_package(GTest CONFIG REQUIRED) + find_package(cce MODULE REQUIRED) + find_package(msprof MODULE REQUIRED) + find_package(SymEngine CONFIG REQUIRED) + find_package(Boost CONFIG REQUIRED) + else() + include(cmake/third_party/json.cmake) + endif() # 自研软件包 find_package(securec MODULE REQUIRED) @@ -111,12 +134,9 @@ if (ENABLE_OPEN_SRC) if (NOT (ENABLE_METADEF_UT OR ENABLE_METADEF_ST)) find_package(mmpa MODULE REQUIRED) endif() - find_package(cce MODULE REQUIRED) - find_package(msprof MODULE REQUIRED) find_package(runtime MODULE REQUIRED) find_package(platform MODULE REQUIRED) - find_package(SymEngine CONFIG REQUIRED) - find_package(Boost CONFIG REQUIRED) + endif() include(cmake/common_funcs.cmake) @@ -193,9 +213,14 @@ if (ENABLE_OPEN_SRC) set(version_info "${ASCEND_INSTALL_PATH}/runtime/version.info") set(install_script_dir "${CMAKE_CURRENT_BINARY_DIR}/install_scripts/") + if(BUILD_WITH_INSTALLED_DEPENDENCY_CANN_PKG_COMMUNITY) + set(ASCEND_SCRIPT_DIR "${ASCEND_INSTALL_PATH}/toolkit/tools/ascend_project/open_install_scripts") + else() + set(ASCEND_SCRIPT_DIR "${ASCEND_INSTALL_PATH}/runtime/script") + endif() add_custom_target(generate_install_script_metadef ALL COMMAND rm -rf ${install_script_dir} - COMMAND cp -rf ${ASCEND_INSTALL_PATH}/toolkit/tools/ascend_project/open_install_scripts ${install_script_dir} + COMMAND cp -rf ${ASCEND_SCRIPT_DIR} ${install_script_dir} COMMAND chmod -R u+w ${install_script_dir} COMMAND echo "base_package=runtime\;compiler" > ${install_script_dir}/version.info COMMAND echo "backup_dir=metadef" >> ${install_script_dir}/version.info @@ -207,18 +232,21 @@ if (ENABLE_OPEN_SRC) FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_READ COMPONENT . EXCLUDE_FROM_ALL ) - - set(CPACK_COMPONENTS_ALL ".;packages") - set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME}) - set(CPACK_PACKAGE_VERSION ${CMAKE_PROJECT_VERSION}) - set(CPACK_PACKAGE_DESCRIPTION "CPack metadef project") - set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CPack metadef project") - set(CPACK_PACKAGE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/package) - set(CPACK_PACKAGE_FILE_NAME "CANN-metadef-linux.${CMAKE_SYSTEM_PROCESSOR}.run") - set(CPACK_GENERATOR External) - set(CPACK_CMAKE_GENERATOR "Unix Makefiles") - set(CPACK_EXTERNAL_ENABLE_STAGING TRUE) - set(CPACK_EXTERNAL_PACKAGE_SCRIPT ${ASCEND_INSTALL_PATH}/toolkit/tools/op_project_templates/ascendc/customize/cmake/makeself.cmake) - set(CPACK_EXTERNAL_BUILT_PACKAGES ${CPACK_PACKAGE_DIRECTORY}/_CPack_Packages/Linux/External/${CPACK_PACKAGE_FILE_NAME}/${CPACK_PACKAGE_FILE_NAME}) - include(CPack) + if(BUILD_WITH_INSTALLED_DEPENDENCY_CANN_PKG_COMMUNITY) + set(CPACK_COMPONENTS_ALL ".;packages") + set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME}) + set(CPACK_PACKAGE_VERSION ${CMAKE_PROJECT_VERSION}) + set(CPACK_PACKAGE_DESCRIPTION "CPack metadef project") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CPack metadef project") + set(CPACK_PACKAGE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/package) + set(CPACK_PACKAGE_FILE_NAME "CANN-metadef-linux.${CMAKE_SYSTEM_PROCESSOR}.run") + set(CPACK_GENERATOR External) + set(CPACK_CMAKE_GENERATOR "Unix Makefiles") + set(CPACK_EXTERNAL_ENABLE_STAGING TRUE) + set(CPACK_EXTERNAL_PACKAGE_SCRIPT ${ASCEND_INSTALL_PATH}/toolkit/tools/op_project_templates/ascendc/customize/cmake/makeself.cmake) + set(CPACK_EXTERNAL_BUILT_PACKAGES ${CPACK_PACKAGE_DIRECTORY}/_CPack_Packages/Linux/External/${CPACK_PACKAGE_FILE_NAME}/${CPACK_PACKAGE_FILE_NAME}) + include(CPack) + else() + include(cmake/package.cmake) + endif() endif() diff --git a/base/registry/op_bin_info.cc b/base/registry/op_bin_info.cc index fa8294a4c5a0ba9d57d1a615941db8fb8a1b07bf..c8a65291d213edb9dabef6ea2c481790131f3d52 100644 --- a/base/registry/op_bin_info.cc +++ b/base/registry/op_bin_info.cc @@ -22,7 +22,7 @@ #include #include #include "op_bin_info_utils.h" -#include "toolchain/dlog_pub.h" +#include "dlog_pub.h" #include "common/ge_common/debug/ge_log.h" namespace ops { diff --git a/build.sh b/build.sh index 39a403aca149fc6dee043fe30b64e739566e5d36..97cff15e116aaf71d6d1afb1e7eea67871fe1acc 100755 --- a/build.sh +++ b/build.sh @@ -12,6 +12,7 @@ set -e BASEPATH=$(cd "$(dirname $0)"; pwd) OUTPUT_PATH="${BASEPATH}/output" +BUILD_OUT_PATH="${BASEPATH}/build_out" BUILD_RELATIVE_PATH="build" # print usage message @@ -32,6 +33,7 @@ usage() { echo " Set output path, default ./output" echo " --enable_symengine" echo " find symengine and boost" + echo " --pkg Build run package with kernel bin" echo "" } @@ -45,12 +47,12 @@ checkopts() { ENABLE_METADEF_COV="off" ENABLE_BENCHMARK="off" GE_ONLY="on" - ASCEND_INSTALL_PATH="/usr/local/Ascend/ascend-toolkit/latest" - ASCEND_3RD_LIB_PATH="$BASEPATH/output/third_party" + ASCEND_INSTALL_PATH="$ASCEND_HOME_PATH" + CANN_3RD_LIB_PATH="$BASEPATH/output/third_party" CMAKE_BUILD_TYPE="Release" # Process the options - parsed_args=$(getopt -a -o j:hv -l help,verbose,enable_symengine,ascend_install_path:,ascend_3rd_lib_path:,output_path: -- "$@") || { + parsed_args=$(getopt -a -o j:hv -l help,verbose,enable_symengine,ascend_install_path:,ascend_3rd_lib_path:,cann_3rd_lib_path:,pkg,output_path: -- "$@") || { usage exit 1 } @@ -76,7 +78,12 @@ checkopts() { shift 2 ;; --ascend_3rd_lib_path) - ASCEND_3RD_LIB_PATH="$(realpath $2)" + CANN_3RD_LIB_PATH="$(realpath $2)" + shift 2 + ;; + --cann_3rd_lib_path) + ASCEND_INSTALL_PATH="$ASCEND_HOME_PATH" + CANN_3RD_LIB_PATH="$(realpath $2)" shift 2 ;; --output_path) @@ -87,6 +94,9 @@ checkopts() { ENABLE_SYMENGINE="on" shift ;; + --pkg) + shift + ;; --) shift break @@ -134,10 +144,11 @@ build_metadef() { -D ENABLE_BENCHMARK=${ENABLE_BENCHMARK} \ -D BUILD_WITHOUT_AIR=True \ -D ASCEND_INSTALL_PATH=${ASCEND_INSTALL_PATH} \ - -D ASCEND_3RD_LIB_PATH=${ASCEND_3RD_LIB_PATH} \ + -D ASCEND_3RD_LIB_PATH=${CANN_3RD_LIB_PATH} \ -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ -D CMAKE_INSTALL_PREFIX=${OUTPUT_PATH} \ - -D ENABLE_SYMENGINE=${ENABLE_SYMENGINE}" + -D ENABLE_SYMENGINE=${ENABLE_SYMENGINE} \ + -D FORCE_REBUILD_CANN_3RD=False" echo "CMAKE_ARGS is: $CMAKE_ARGS" cmake_generate_make "${BUILD_PATH}" "${CMAKE_ARGS}" @@ -149,7 +160,17 @@ build_metadef() { echo "execute command: make ${VERBOSE} -j${THREAD_NUM} && make install failed." return 1 fi - [ -n "$(ls ${OUTPUT_PATH}/CANN-*.run 2>/dev/null)" ] && mv -f ${OUTPUT_PATH}/CANN-*.run ${OUTPUT_PATH}/package/ + if [ -d "${BASEPATH}/../open_source" ]; then + echo "Dir ${BASEPATH}/../open_source exist." + mv ${BUILD_PATH}_CPack_Packages/makeself_staging/cann-*.run ${OUTPUT_PATH}/ + cp ${OUTPUT_PATH}/cann-*.run ${BUILD_OUT_PATH}/ + + ls -l ${OUTPUT_PATH}/cann-*.run + ls -l ${BUILD_OUT_PATH}/cann-*.run + else + echo "Dir ${BASEPATH}/../open_source not exist." + [ -n "$(ls ${OUTPUT_PATH}/CANN-*.run 2>/dev/null)" ] && mv -f ${OUTPUT_PATH}/CANN-*.run ${OUTPUT_PATH}/package/ + fi echo "Metadef build success!" } @@ -159,6 +180,7 @@ main() { g++ -v mk_dir ${OUTPUT_PATH} + mk_dir ${BUILD_OUT_PATH} echo "---------------- Metadef build start ----------------" build_metadef || { echo "Metadef build failed."; exit 1; } echo "---------------- Metadef build finished ----------------" diff --git a/cmake/makeself.cmake b/cmake/makeself.cmake new file mode 100644 index 0000000000000000000000000000000000000000..1d142ba73ac046982f639d6547b8fb7fe952f29a --- /dev/null +++ b/cmake/makeself.cmake @@ -0,0 +1,101 @@ +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- +# makeself.cmake - 自定义 makeself 打包脚本 + +# 设置 makeself 路径 +set(MAKESELF_EXE ${CPACK_MAKESELF_PATH}/makeself.sh) +set(MAKESELF_HEADER_EXE ${CPACK_MAKESELF_PATH}/makeself-header.sh) +if(NOT MAKESELF_EXE) + message(FATAL_ERROR "makeself not found! Install it with: sudo apt install makeself") +endif() + +# 创建临时安装目录 +set(STAGING_DIR "${CPACK_CMAKE_BINARY_DIR}/_CPack_Packages/makeself_staging") +file(MAKE_DIRECTORY "${STAGING_DIR}") + +# 执行安装到临时目录 +execute_process( + COMMAND "${CMAKE_COMMAND}" --install "${CPACK_CMAKE_BINARY_DIR}" --prefix "${STAGING_DIR}" + RESULT_VARIABLE INSTALL_RESULT +) + +message("Remove files from ${CPACK_CMAKE_BINARY_DIR}/_CPack_Packages/makeself_staging/lib") +file(GLOB ALL_FILES "${CPACK_CMAKE_BINARY_DIR}/_CPack_Packages/makeself_staging/lib/*") # * 匹配所有文件/目录 + +# 删除lib目录下所有install的文件,这些是各个cmake中install的,子包中不应该在这个目录下面,参见package.cmake中新install的内容 +file(REMOVE_RECURSE + "${CPACK_CMAKE_BINARY_DIR}/_CPack_Packages/makeself_staging/lib" # 递归删除目录及内容 +) + +if(NOT INSTALL_RESULT EQUAL 0) + message(FATAL_ERROR "Installation to staging directory failed: ${INSTALL_RESULT}") +endif() +# 生成安装配置文件 +set(CSV_OUTPUT ${CPACK_CMAKE_BINARY_DIR}/filelist.csv) + +execute_process( + COMMAND python3 ${CPACK_CMAKE_SOURCE_DIR}/scripts/package/package.py --pkg_name metadef --os_arch linux-${CPACK_ARCH} + WORKING_DIRECTORY ${CPACK_CMAKE_BINARY_DIR} + OUTPUT_VARIABLE result + ERROR_VARIABLE error + RESULT_VARIABLE code + OUTPUT_STRIP_TRAILING_WHITESPACE +) +message(STATUS "package.py result: ${code}") +if (NOT code EQUAL 0) + message(FATAL_ERROR "Filelist generation failed: ${result}") +else () + message(STATUS "Filelist generated successfully: ${result}") + + if (NOT EXISTS ${CSV_OUTPUT}) + message(FATAL_ERROR "Output file not created: ${CSV_OUTPUT}") + endif () +endif () +set(SCENE_OUT_PUT + ${CPACK_CMAKE_BINARY_DIR}/scene.info +) +configure_file( + ${SCENE_OUT_PUT} + ${STAGING_DIR}/metadef/ + COPYONLY +) +set(OPS_VERSION_OUT_PUT + ${CPACK_CMAKE_BINARY_DIR}/metadef_version.h +) +configure_file( + ${OPS_VERSION_OUT_PUT} + ${STAGING_DIR}/metadef/ + COPYONLY +) +configure_file( + ${CSV_OUTPUT} + ${STAGING_DIR}/metadef/script + COPYONLY +) + +# makeself打包 +file(STRINGS ${CPACK_CMAKE_BINARY_DIR}/makeself.txt script_output) +string(REPLACE " " ";" makeself_param_string "${script_output}") + +message(STATUS "script output: ${script_output}") +message(STATUS "makeself: ${makeself_param_string}") + +execute_process(COMMAND bash ${MAKESELF_EXE} + --header ${MAKESELF_HEADER_EXE} + --help-header metadef/script/help.info + ${makeself_param_string} metadef/script/install.sh + WORKING_DIRECTORY ${STAGING_DIR} + RESULT_VARIABLE EXEC_RESULT + ERROR_VARIABLE EXEC_ERROR +) + +if(NOT EXEC_RESULT EQUAL 0) + message(FATAL_ERROR "makeself packaging failed: ${EXEC_ERROR}") +endif() diff --git a/cmake/modules/Findunified_dlog.cmake b/cmake/modules/Findunified_dlog.cmake index 0998b6f172795d5cb425477f629491d38992232a..9cf28c87590fca361c6d070fc0618850b9ea0cba 100644 --- a/cmake/modules/Findunified_dlog.cmake +++ b/cmake/modules/Findunified_dlog.cmake @@ -78,7 +78,7 @@ if(unified_dlog_FOUND) add_library(unified_dlog_headers INTERFACE IMPORTED) set_target_properties(unified_dlog_headers PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${unified_dlog_INCLUDE_DIR}" + INTERFACE_INCLUDE_DIRECTORIES "${unified_dlog_INCLUDE_DIR};${unified_dlog_INCLUDE_DIR}/toolchain" ) include(CMakePrintHelpers) diff --git a/cmake/modules/sub_module/Findcce.cmake b/cmake/modules/sub_module/Findcce.cmake new file mode 100644 index 0000000000000000000000000000000000000000..080cb5fb03e34f20809aaf321ed6d1a86c1a12b1 --- /dev/null +++ b/cmake/modules/sub_module/Findcce.cmake @@ -0,0 +1,46 @@ +# Copyright (c) 2024 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ====================================================================================================================== + +if (cce_FOUND) + message(STATUS "Package cce has been found.") + return() +endif() + +find_path(_INCLUDE_DIR + NAMES experiment/cce/cce_def.hpp + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(cce + FOUND_VAR + cce_FOUND + REQUIRED_VARS + _INCLUDE_DIR +) + +if(cce_FOUND) + set(cce_INCLUDE_DIR "${_INCLUDE_DIR}/experiment") + include(CMakePrintHelpers) + message(STATUS "Variables in cce module:") + cmake_print_variables(cce_INCLUDE_DIR) + + add_library(cce_headers INTERFACE IMPORTED) + set_target_properties(cce_headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${cce_INCLUDE_DIR};${cce_INCLUDE_DIR}/cce" + ) + + include(CMakePrintHelpers) + cmake_print_properties(TARGETS cce_headers + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ) +endif() + +# Cleanup temporary variables. +set(_INCLUDE_DIR) diff --git a/cmake/modules/sub_module/Findmmpa.cmake b/cmake/modules/sub_module/Findmmpa.cmake new file mode 100644 index 0000000000000000000000000000000000000000..7e79f3b7a94dfe0397156b39d0e66697d51a25a9 --- /dev/null +++ b/cmake/modules/sub_module/Findmmpa.cmake @@ -0,0 +1,111 @@ +# Copyright (c) 2024 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ====================================================================================================================== + +if (mmpa_FOUND) + message(STATUS "Package mmpa has been found.") + return() +endif() + +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS mmpa static_mmpa mmpa_headers) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) + +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() + +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + +find_path(_INCLUDE_DIR + NAMES include/mmpa/mmpa_api.h + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(mmpa_SHARED_LIBRARY + NAMES libmmpa.so + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(mmpa_STATIC_LIBRARY + NAMES libmmpa.a + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(mmpa + FOUND_VAR + mmpa_FOUND + REQUIRED_VARS + _INCLUDE_DIR + mmpa_SHARED_LIBRARY + mmpa_STATIC_LIBRARY +) + +if(mmpa_FOUND) + set(mmpa_INCLUDE_DIR "${_INCLUDE_DIR}/include") + include(CMakePrintHelpers) + message(STATUS "Variables in mmpa module:") + cmake_print_variables(mmpa_INCLUDE_DIR) + cmake_print_variables(mmpa_SHARED_LIBRARY) + cmake_print_variables(mmpa_STATIC_LIBRARY) + + add_library(mmpa SHARED IMPORTED) + set_target_properties(mmpa PROPERTIES + INTERFACE_LINK_LIBRARIES "mmpa_headers" + IMPORTED_LOCATION "${mmpa_SHARED_LIBRARY}" + ) + + add_library(static_mmpa STATIC IMPORTED) + set_target_properties(static_mmpa PROPERTIES + INTERFACE_LINK_LIBRARIES "mmpa_headers" + IMPORTED_LOCATION "${mmpa_STATIC_LIBRARY}" + ) + + add_library(mmpa_headers INTERFACE IMPORTED) + set_target_properties(mmpa_headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${mmpa_INCLUDE_DIR};${mmpa_INCLUDE_DIR}/mmpa" + ) + + include(CMakePrintHelpers) + cmake_print_properties(TARGETS mmpa + PROPERTIES INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS static_mmpa + PROPERTIES INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS mmpa_headers + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ) +endif() + +# Cleanup temporary variables. +set(_INCLUDE_DIR) diff --git a/cmake/modules/sub_module/Findmsprof.cmake b/cmake/modules/sub_module/Findmsprof.cmake new file mode 100644 index 0000000000000000000000000000000000000000..c8524a34496444297b5199f869f41cb8ac32be38 --- /dev/null +++ b/cmake/modules/sub_module/Findmsprof.cmake @@ -0,0 +1,111 @@ +# Copyright (c) 2024 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ====================================================================================================================== + +if (msprof_FOUND) + message(STATUS "Package msprof has been found.") + return() +endif() + +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS msprofiler_fwk_share profapi_share msprof_headers) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) + +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() + +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + +find_path(_INCLUDE_DIR + NAMES runtime/pkg_inc/profiling/prof_api.h + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(msprofiler_SHARED_LIBRARY + NAMES libmsprofiler.so + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(profapi_SHARED_LIBRARY + NAMES libprofapi.so + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(msprof + FOUND_VAR + msprof_FOUND + REQUIRED_VARS + _INCLUDE_DIR + msprofiler_SHARED_LIBRARY + profapi_SHARED_LIBRARY +) + +if(msprof_FOUND) + set(msprof_INCLUDE_DIR "${_INCLUDE_DIR}/experiment") + include(CMakePrintHelpers) + message(STATUS "Variables in msprof module:") + cmake_print_variables(msprof_INCLUDE_DIR) + cmake_print_variables(msprofiler_SHARED_LIBRARY) + cmake_print_variables(profapi_SHARED_LIBRARY) + + add_library(msprofiler_fwk_share SHARED IMPORTED) + set_target_properties(msprofiler_fwk_share PROPERTIES + INTERFACE_LINK_LIBRARIES "msprof_headers" + IMPORTED_LOCATION "${msprofiler_SHARED_LIBRARY}" + ) + + add_library(profapi_share SHARED IMPORTED) + set_target_properties(profapi_share PROPERTIES + INTERFACE_LINK_LIBRARIES "msprof_headers" + IMPORTED_LOCATION "${profapi_SHARED_LIBRARY}" + ) + + add_library(msprof_headers INTERFACE IMPORTED) + set_target_properties(msprof_headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${msprof_INCLUDE_DIR};${msprof_INCLUDE_DIR}/msprof;${msprof_INCLUDE_DIR}/msprof/toolchain" + ) + + include(CMakePrintHelpers) + cmake_print_properties(TARGETS msprofiler_fwk_share + PROPERTIES INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS profapi_share + PROPERTIES INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS msprof_headers + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ) +endif() + +# Cleanup temporary variables. +set(_INCLUDE_DIR) diff --git a/cmake/modules/sub_module/Findplatform.cmake b/cmake/modules/sub_module/Findplatform.cmake new file mode 100644 index 0000000000000000000000000000000000000000..35a09f36160869bbd9665db5abdb62ab28e5a47a --- /dev/null +++ b/cmake/modules/sub_module/Findplatform.cmake @@ -0,0 +1,94 @@ +# Copyright (c) 2024 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ====================================================================================================================== + +if (platform_FOUND) + message(STATUS "Package platform has been found.") + return() +endif() + +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS platform platform_headers) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) + +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() + +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + +find_path(_INCLUDE_DIR + NAMES include/platform/platform_info.h + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(platform_SHARED_LIBRARY + NAMES libplatform.so + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(platform + FOUND_VAR + platform_FOUND + REQUIRED_VARS + _INCLUDE_DIR + platform_SHARED_LIBRARY +) + +if(platform_FOUND) + set(platform_INCLUDE_DIR "${_INCLUDE_DIR}") + include(CMakePrintHelpers) + message(STATUS "Variables in platform module:") + cmake_print_variables(platform_INCLUDE_DIR) + cmake_print_variables(platform_SHARED_LIBRARY) + + add_library(platform SHARED IMPORTED) + set_target_properties(platform PROPERTIES + INTERFACE_LINK_LIBRARIES "platform_headers" + IMPORTED_LOCATION "${platform_SHARED_LIBRARY}" + ) + + add_library(platform_headers INTERFACE IMPORTED) + set_target_properties(platform_headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${platform_INCLUDE_DIR};${platform_INCLUDE_DIR}/include;${platform_INCLUDE_DIR}/include/platform" + ) + + include(CMakePrintHelpers) + cmake_print_properties(TARGETS platform + PROPERTIES INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS platform_headers + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ) +endif() + +# Cleanup temporary variables. +set(_INCLUDE_DIR) diff --git a/cmake/modules/sub_module/Findruntime.cmake b/cmake/modules/sub_module/Findruntime.cmake new file mode 100644 index 0000000000000000000000000000000000000000..158d05453f5c384b6e7c94372f61b9ad482c9e25 --- /dev/null +++ b/cmake/modules/sub_module/Findruntime.cmake @@ -0,0 +1,94 @@ +# Copyright (c) 2024 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ====================================================================================================================== + +if (runtime_FOUND) + message(STATUS "Package runtime has been found.") + return() +endif() + +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS runtime runtime_headers) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) + +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() + +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + +find_path(_INCLUDE_DIR + NAMES pkg_inc/runtime/rt_external.h + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(runtime_SHARED_LIBRARY + NAMES libruntime.so + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(runtime + FOUND_VAR + runtime_FOUND + REQUIRED_VARS + _INCLUDE_DIR + runtime_SHARED_LIBRARY +) + +if(runtime_FOUND) + set(runtime_INCLUDE_DIR "${_INCLUDE_DIR}") + include(CMakePrintHelpers) + message(STATUS "Variables in runtime module:") + cmake_print_variables(runtime_INCLUDE_DIR) + cmake_print_variables(runtime_SHARED_LIBRARY) + + add_library(runtime SHARED IMPORTED) + set_target_properties(runtime PROPERTIES + INTERFACE_LINK_LIBRARIES "runtime_headers" + IMPORTED_LOCATION "${runtime_SHARED_LIBRARY}" + ) + + add_library(runtime_headers INTERFACE IMPORTED) + set_target_properties(runtime_headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${runtime_INCLUDE_DIR};${runtime_INCLUDE_DIR}/pkg_inc;${runtime_INCLUDE_DIR}/pkg_inc/runtime" + ) + + include(CMakePrintHelpers) + cmake_print_properties(TARGETS runtime + PROPERTIES INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS runtime_headers + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ) +endif() + +# Cleanup temporary variables. +set(_INCLUDE_DIR) diff --git a/cmake/modules/sub_module/Findsecurec.cmake b/cmake/modules/sub_module/Findsecurec.cmake new file mode 100644 index 0000000000000000000000000000000000000000..05424bcc2ff62bfdea64fcf16d64091532c7bfba --- /dev/null +++ b/cmake/modules/sub_module/Findsecurec.cmake @@ -0,0 +1,99 @@ +# Copyright (c) 2024 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ====================================================================================================================== + +if (securec_FOUND) + message(STATUS "Package securec has been found.") + return() +endif() + +find_path(C_SEC_INCLUDE NAMES securec.h) +if(WIN32) + find_library(C_SEC_STATIC_LIBRARY NAMES libc_sec_static.lib) + find_file(C_SEC_SHARED_DLL NAMES libc_sec.dll PATH_SUFFIXES lib) + find_library(C_SEC_IMPLIB NAMES libc_sec.lib) +else() + find_library(C_SEC_STATIC_LIBRARY NAMES libc_sec.a PATH_SUFFIXES lib64) + find_library(C_SEC_SHARED_LIBRARY NAMES libc_sec.so PATH_SUFFIXES lib64) +endif() + +include(FindPackageHandleStandardArgs) +if(WIN32) + find_package_handle_standard_args(securec + FOUND_VAR + securec_FOUND + REQUIRED_VARS + C_SEC_INCLUDE + C_SEC_STATIC_LIBRARY + C_SEC_SHARED_DLL + C_SEC_IMPLIB + ) +elseif("${ENABLE_SECUREC_SHARED}" STREQUAL "OFF") + find_package_handle_standard_args(securec + FOUND_VAR + securec_FOUND + REQUIRED_VARS + C_SEC_INCLUDE + C_SEC_STATIC_LIBRARY + ) +else() + find_package_handle_standard_args(securec + FOUND_VAR + securec_FOUND + REQUIRED_VARS + C_SEC_INCLUDE + C_SEC_STATIC_LIBRARY + C_SEC_SHARED_LIBRARY + ) +endif() + +if(securec_FOUND) + set(C_SEC_INCLUDE_DIR ${C_SEC_INCLUDE}) + get_filename_component(C_SEC_LIBRARY_DIR ${C_SEC_SHARED_LIBRARY} DIRECTORY) + + include(CMakePrintHelpers) + message(STATUS "Variables in securec module:") + cmake_print_variables(C_SEC_INCLUDE) + cmake_print_variables(C_SEC_LIBRARY_DIR) + cmake_print_variables(C_SEC_STATIC_LIBRARY) + cmake_print_variables(C_SEC_SHARED_LIBRARY) + + add_library(c_sec_headers INTERFACE IMPORTED) + target_include_directories(c_sec_headers INTERFACE ${C_SEC_INCLUDE}) + + add_library(c_sec_static STATIC IMPORTED) + set_target_properties(c_sec_static PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${C_SEC_INCLUDE}" + IMPORTED_LOCATION "${C_SEC_STATIC_LIBRARY}" + ) + + add_library(c_sec SHARED IMPORTED) + if(WIN32) + set_target_properties(c_sec PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${C_SEC_INCLUDE}" + IMPORTED_IMPLIB "${C_SEC_IMPLIB}" + IMPORTED_LOCATION "${C_SEC_SHARED_DLL}" + ) + else() + set_target_properties(c_sec PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${C_SEC_INCLUDE}" + IMPORTED_LOCATION "${C_SEC_SHARED_LIBRARY}" + ) + endif() + + include(CMakePrintHelpers) + cmake_print_properties(TARGETS c_sec_headers + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ) + cmake_print_properties(TARGETS c_sec_static + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS c_sec + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES IMPORTED_LOCATION + ) +endif() diff --git a/cmake/modules/sub_module/Findslog.cmake b/cmake/modules/sub_module/Findslog.cmake new file mode 100644 index 0000000000000000000000000000000000000000..718d162d5778a873578126424bea1c23c0818fa9 --- /dev/null +++ b/cmake/modules/sub_module/Findslog.cmake @@ -0,0 +1,113 @@ +# Copyright (c) 2024 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ====================================================================================================================== + +if (slog_FOUND) + message(STATUS "Package slog has been found.") + return() +endif() + +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS slog alog slog_headers) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) + +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() + +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + +find_path(_INCLUDE_DIR + NAMES pkg_inc/base/dlog_pub.h + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(slog_SHARED_LIBRARY + NAMES libascendalog.so + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(alog_SHARED_LIBRARY + NAMES libascendalog.so + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(slog + FOUND_VAR + slog_FOUND + REQUIRED_VARS + _INCLUDE_DIR + slog_SHARED_LIBRARY + alog_SHARED_LIBRARY +) + +if(slog_FOUND) + set(slog_INCLUDE_DIR "${_INCLUDE_DIR}") + include(CMakePrintHelpers) + message(STATUS "Variables in slog module:") + cmake_print_variables(slog_INCLUDE_DIR) + cmake_print_variables(slog_SHARED_LIBRARY) + cmake_print_variables(alog_SHARED_LIBRARY) + + add_library(slog SHARED IMPORTED) + set_target_properties(slog PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "LOG_CPP;PROCESS_LOG" + INTERFACE_LINK_LIBRARIES "slog_headers" + IMPORTED_LOCATION "${slog_SHARED_LIBRARY}" + ) + + add_library(alog SHARED IMPORTED) + set_target_properties(alog PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "LOG_CPP;PROCESS_LOG" + INTERFACE_LINK_LIBRARIES "slog_headers" + IMPORTED_LOCATION "${alog_SHARED_LIBRARY}" + ) + + add_library(slog_headers INTERFACE IMPORTED) + set_target_properties(slog_headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${slog_INCLUDE_DIR};${slog_INCLUDE_DIR}/pkg_inc;${slog_INCLUDE_DIR}/pkg_inc/base" + ) + + include(CMakePrintHelpers) + cmake_print_properties(TARGETS slog + PROPERTIES INTERFACE_COMPILE_DEFINITIONS INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS alog + PROPERTIES INTERFACE_COMPILE_DEFINITIONS INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS slog_headers + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ) +endif() + +# Cleanup temporary variables. +set(_INCLUDE_DIR) diff --git a/cmake/modules/sub_module/Findunified_dlog.cmake b/cmake/modules/sub_module/Findunified_dlog.cmake new file mode 100644 index 0000000000000000000000000000000000000000..00b1d5d418da53a0bfcac15dff67943452f44f09 --- /dev/null +++ b/cmake/modules/sub_module/Findunified_dlog.cmake @@ -0,0 +1,94 @@ +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ====================================================================================================================== + +if (unified_dlog_FOUND) + message(STATUS "Package unified_dlog has been found.") + return() +endif() + +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS unified_dlog unified_dlog_headers) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) + +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() + +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + +find_path(_INCLUDE_DIR + NAMES pkg_inc/base/dlog_pub.h + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +find_library(unified_dlog_SHARED_LIBRARY + NAMES libunified_dlog.so + PATH_SUFFIXES lib64 + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(unified_dlog + FOUND_VAR + unified_dlog_FOUND + REQUIRED_VARS + _INCLUDE_DIR + unified_dlog_SHARED_LIBRARY +) + +if(unified_dlog_FOUND) + set(unified_dlog_INCLUDE_DIR "${_INCLUDE_DIR}") + include(CMakePrintHelpers) + message(STATUS "Variables in unified_dlog module:") + cmake_print_variables(unified_dlog_INCLUDE_DIR) + cmake_print_variables(unified_dlog_SHARED_LIBRARY) + + add_library(unified_dlog SHARED IMPORTED) + set_target_properties(unified_dlog PROPERTIES + INTERFACE_LINK_LIBRARIES "unified_dlog_headers" + IMPORTED_LOCATION "${unified_dlog_SHARED_LIBRARY}" + ) + + add_library(unified_dlog_headers INTERFACE IMPORTED) + set_target_properties(unified_dlog_headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${unified_dlog_INCLUDE_DIR};${unified_dlog_INCLUDE_DIR}/pkg_inc;${unified_dlog_INCLUDE_DIR}/pkg_inc/base" + ) + + include(CMakePrintHelpers) + cmake_print_properties(TARGETS unified_dlog + PROPERTIES INTERFACE_LINK_LIBRARIES IMPORTED_LOCATION + ) + cmake_print_properties(TARGETS unified_dlog_headers + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ) +endif() + +# Cleanup temporary variables. +set(_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/package.cmake b/cmake/package.cmake new file mode 100644 index 0000000000000000000000000000000000000000..d5d99d14bd5880439f951174b067a2de64f04600 --- /dev/null +++ b/cmake/package.cmake @@ -0,0 +1,230 @@ +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +#### CPACK to package run ##### +message(STATUS "System processor: ${CMAKE_SYSTEM_PROCESSOR}") +if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + message(STATUS "Detected architecture: x86_64") + set(ARCH x86_64) +elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|arm") + message(STATUS "Detected architecture: ARM64") + set(ARCH aarch64) +else () + message(WARNING "Unknown architecture: ${CMAKE_SYSTEM_PROCESSOR}") + set(ARCH ${CMAKE_SYSTEM_PROCESSOR}) +endif () +# 打印路径 +message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}") +message(STATUS "CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}") +message(STATUS "CMAKE_BINARY_DIR = ${CMAKE_BINARY_DIR}") +set(ARCH_LINUX_PATH "${ARCH}-linux") +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/third_party/makeself-fetch.cmake) + +# ============= 组件打包 ============= +function(install_public_packages) + set(script_prefix ${CMAKE_CURRENT_SOURCE_DIR}/scripts/package/metadef/scripts) + install(DIRECTORY ${script_prefix}/ + DESTINATION metadef/script + FILE_PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE # 文件权限 + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + DIRECTORY_PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE # 目录权限 + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + ) + set(SCRIPTS_FILES + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/check_version_required.awk + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/common_func.inc + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/common_interface.bash + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/common_interface.csh + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/common_interface.fish + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/version_compatiable.inc + ) + + install(FILES ${SCRIPTS_FILES} + DESTINATION metadef/script + ) + set(COMMON_FILES + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/install_common_parser.sh + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/common_func_v2.inc + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/common_installer.inc + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/script_operator.inc + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/version_cfg.inc + ) + + set(PACKAGE_FILES + ${COMMON_FILES} + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/multi_version.inc + ) + set(LATEST_MANGER_FILES + ${COMMON_FILES} + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/common_func.inc + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/version_compatiable.inc + ${CMAKE_SOURCE_DIR}/scripts/package/common/sh/check_version_required.awk + ) + set(CONF_FILES + ${CMAKE_SOURCE_DIR}/scripts/package/common/cfg/path.cfg + ) + install(FILES ${CMAKE_SOURCE_DIR}/version.info + DESTINATION . + ) + install(FILES ${CONF_FILES} + DESTINATION metadef/conf + ) + install(FILES ${PACKAGE_FILES} + DESTINATION metadef/script + ) + install(FILES ${LATEST_MANGER_FILES} + DESTINATION latest_manager + ) + install(DIRECTORY ${CMAKE_SOURCE_DIR}/scripts/package/latest_manager/scripts/ + DESTINATION latest_manager + ) + set(BIN_FILES + ${CMAKE_SOURCE_DIR}/scripts/package/metadef/scripts/prereq_check.bash + ${CMAKE_SOURCE_DIR}/scripts/package/metadef/scripts/prereq_check.csh + ${CMAKE_SOURCE_DIR}/scripts/package/metadef/scripts/prereq_check.fish + ${CMAKE_SOURCE_DIR}/scripts/package/metadef/scripts/setenv.bash + ${CMAKE_SOURCE_DIR}/scripts/package/metadef/scripts/setenv.csh + ${CMAKE_SOURCE_DIR}/scripts/package/metadef/scripts/setenv.fish + ) + install(FILES ${BIN_FILES} + DESTINATION metadef/bin + ) +endfunction() + +# ============= 创建install ============= +install_public_packages() + +message(STATUS "************Install metadef packages***************") +install(TARGETS exe_meta_device exe_graph rt2_registry_static opp_registry metadef + LIBRARY DESTINATION metadef/lib64 + ARCHIVE DESTINATION metadef/lib64 +) +install(TARGETS rt2_registry_static opp_registry exe_graph metadef + LIBRARY DESTINATION metadef/lib64/stub/linux/x86_64 + ARCHIVE DESTINATION metadef/lib64/stub/linux/x86_64 +) +install(TARGETS rt2_registry_static opp_registry exe_graph metadef + LIBRARY DESTINATION metadef/lib64/stub/linux/aarch64 + ARCHIVE DESTINATION metadef/lib64/stub/linux/aarch64 +) +install(TARGETS rt2_registry_static opp_registry exe_graph metadef + LIBRARY DESTINATION metadef/lib64/stub/minios/aarch64 + ARCHIVE DESTINATION metadef/lib64/stub/minios/aarch64 +) +install(TARGETS rt2_registry_static opp_registry exe_graph metadef + LIBRARY DESTINATION metadef/lib64/stub/aoskernel/aarch64 + ARCHIVE DESTINATION metadef/lib64/stub/aoskernel/aarch64 +) +install(TARGETS exe_meta_device + LIBRARY DESTINATION metadef/lib64/device/lib64 + ARCHIVE DESTINATION metadef/lib64/device/lib64 +) + +set(EXTERNAL_RUNTIME_FILES + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/tiling_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/kernel_run_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/shape.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/compute_node_info.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/tensor_data.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/op_execute_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/storage_format.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/tensor.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/continuous_vector.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/infer_shape_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/range.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/runtime_attrs.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/base_type.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/expand_dims_type.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/infer_datatype_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/infer_shape_range_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/context_extend.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/storage_shape.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/tiling_parse_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/kernel_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/tiling_data.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/extended_kernel_context.h + ${CMAKE_SOURCE_DIR}/inc/external/exe_graph/runtime/op_execute_prepare_context.h + ${CMAKE_SOURCE_DIR}/inc/exe_graph/runtime/gert_tensor_data.h +) +install(FILES ${EXTERNAL_RUNTIME_FILES} + DESTINATION metadef/include/exe_graph/runtime +) +set(EXTERNAL_GRAPH_FILES + ${CMAKE_SOURCE_DIR}/inc/external/graph/tensor.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/c_types.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/ge_error_codes.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/compiler_def.h + ${CMAKE_SOURCE_DIR}/inc/graph/op_desc.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/ascend_string.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/attr_value.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/operator.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/operator_factory.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/resource_context.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/inference_context.h + ${CMAKE_SOURCE_DIR}/inc/external/graph/types.h +) +install(FILES ${EXTERNAL_GRAPH_FILES} + DESTINATION metadef/include/graph +) +install(FILES ${CMAKE_SOURCE_DIR}/inc/external/graph/utils/type_utils.h + DESTINATION metadef/include/graph/utils +) +install(FILES ${CMAKE_SOURCE_DIR}/inc/external/utils/extern_math_util.h + DESTINATION metadef/include/utils +) +install(FILES ${CMAKE_SOURCE_DIR}/inc/external/ge/ge_allocator.h + ${CMAKE_SOURCE_DIR}/inc/external/ge_common/ge_api_types.h + DESTINATION metadef/include/ge +) +install(FILES ${CMAKE_SOURCE_DIR}/inc/external/ge_common/ge_api_types.h + ${CMAKE_SOURCE_DIR}/inc/external/ge_common/ge_api_error_codes.h + ${CMAKE_SOURCE_DIR}/inc/external/ge_common/ge_error_codes.h + DESTINATION metadef/include/external/ge_common +) +install(FILES ${CMAKE_SOURCE_DIR}/inc/external/base/registry/op_impl_space_registry_v2.h + ${CMAKE_SOURCE_DIR}/inc/external/base/registry/opp_package_utils.h + DESTINATION metadef/pkg_inc/base/registry +) +install(FILES ${CMAKE_SOURCE_DIR}/inc/external/base/context_builder/op_tiling_parse_context_builder.h + ${CMAKE_SOURCE_DIR}/inc/external/base/context_builder/op_tiling_context_builder.h + DESTINATION metadef/include/base/context_builder +) +set(EXTERNAL_REGISTRY_FILES + ${CMAKE_SOURCE_DIR}/inc/external/register/op_impl_registry.h + ${CMAKE_SOURCE_DIR}/inc/external/register/op_impl_kernel_registry.h + ${CMAKE_SOURCE_DIR}/inc/external/register/register_types.h + ${CMAKE_SOURCE_DIR}/inc/external/register/register_fmk_types.h + ${CMAKE_SOURCE_DIR}/inc/external/register/register_error_codes.h +) +install(FILES ${EXTERNAL_REGISTRY_FILES} + DESTINATION metadef/include/register +) + +# ============= CPack ============= + +set(CPACK_COMPONENTS_ALL ".;packages") +set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") +set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") +set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}") +set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}") +set(CPACK_CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}") +set(CPACK_CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}") +set(CPACK_MAKESELF_PATH "${MAKESELF_PATH}") +set(CPACK_ARCH "${ARCH}") +set(CPACK_GENERATOR External) +set(CPACK_EXTERNAL_ENABLE_STAGING TRUE) +set(CPACK_EXTERNAL_PACKAGE_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/makeself.cmake") + +message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}") +include(CPack) \ No newline at end of file diff --git a/cmake/third_party/json.cmake b/cmake/third_party/json.cmake new file mode 100644 index 0000000000000000000000000000000000000000..711c9a2184a161fd6ca2de15dbeb6fb91ad7c743 --- /dev/null +++ b/cmake/third_party/json.cmake @@ -0,0 +1,69 @@ +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +include_guard(GLOBAL) + +if(json_FOUND) + return() +endif() + +unset(json_FOUND CACHE) +unset(JSON_INCLUDE CACHE) + +if(NOT ASCEND_3RD_LIB_PATH) + set(ASCEND_3RD_LIB_PATH ${PROJECT_SOURCE_DIR}/third_party) +endif() +if(NOT CANN_3RD_PKG_PATH) + set(CANN_3RD_PKG_PATH ${PROJECT_SOURCE_DIR}/third_party/pkg) +endif() + +set(JSON_DOWNLOAD_PATH ${CANN_3RD_PKG_PATH}) +set(JSON_INSTALL_PATH ${ASCEND_3RD_LIB_PATH}/json) + +find_path(JSON_INCLUDE + NAMES nlohmann/json.hpp + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH + PATHS ${JSON_INSTALL_PATH}/include) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(json + FOUND_VAR + json_FOUND + REQUIRED_VARS + JSON_INCLUDE + ) +if(json_FOUND AND NOT FORCE_REBUILD_CANN_3RD) + message("json found in ${JSON_INSTALL_PATH}, and not force rebuild cann third_party") + set(JSON_INCLUDE_DIR ${JSON_INSTALL_PATH}/include) + add_library(json INTERFACE) + target_include_directories(json INTERFACE ${JSON_INCLUDE_DIR}) +else() + set(REQ_URL "https://gitcode.com/cann-src-third-party/json/releases/download/v3.11.3/include.zip") + include(ExternalProject) + ExternalProject_Add(third_party_json + URL ${REQ_URL} + TLS_VERIFY OFF + DOWNLOAD_DIR ${JSON_DOWNLOAD_PATH} + SOURCE_DIR ${JSON_INSTALL_PATH} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND + ${CMAKE_COMMAND} -E make_directory ${JSON_INSTALL_PATH} && + ${CMAKE_COMMAND} -E chdir ${JSON_INSTALL_PATH} ${CMAKE_COMMAND} -E tar xf "${JSON_DOWNLOAD_PATH}/include.zip" --format=zip + UPDATE_COMMAND "" + ) + ExternalProject_Get_Property(third_party_json SOURCE_DIR) + ExternalProject_Get_Property(third_party_json BINARY_DIR) + set(JSON_INCLUDE_DIR ${SOURCE_DIR}/include) + add_library(json INTERFACE) + target_include_directories(json INTERFACE ${JSON_INCLUDE_DIR}) + add_dependencies(json third_party_json) +endif() diff --git a/cmake/third_party/makeself-fetch.cmake b/cmake/third_party/makeself-fetch.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6691730a07cc945acde0d85645fb974168f76dbd --- /dev/null +++ b/cmake/third_party/makeself-fetch.cmake @@ -0,0 +1,39 @@ +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +set(MAKESELF_NAME "makeself") +set(MAKESELF_PATH "${ASCEND_3RD_LIB_PATH}/${MAKESELF_NAME}") + +if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) +endif() +# 默认配置的makeself还是不存在则下载 +if (NOT EXISTS "${MAKESELF_PATH}/makeself-header.sh" OR NOT EXISTS "${MAKESELF_PATH}/makeself.sh") + set(MAKESELF_URL "https://gitcode.com/cann-src-third-party/makeself/releases/download/release-2.5.0-patch1.0/makeself-release-2.5.0-patch1.tar.gz") + message(STATUS "Downloading ${MAKESELF_NAME} from ${MAKESELF_URL}") + + include(FetchContent) + FetchContent_Declare( + ${MAKESELF_NAME} + URL ${MAKESELF_URL} + URL_HASH SHA256=bfa730a5763cdb267904a130e02b2e48e464986909c0733ff1c96495f620369a + SOURCE_DIR "${MAKESELF_PATH}" # 直接解压到此目录 + ) + FetchContent_MakeAvailable(${MAKESELF_NAME}) + execute_process( + COMMAND chmod 700 "${MAKESELF_PATH}/makeself.sh" + COMMAND chmod 700 "${MAKESELF_PATH}/makeself-header.sh" + -E env + CMAKE_TLS_VERIFY=0 + RESULT_VARIABLE CHMOD_RESULT + ERROR_VARIABLE CHMOD_ERROR + ) +endif() \ No newline at end of file diff --git a/error_manager/error_code.json b/error_manager/error_code.json index 79afea13a35353a7dd5a1ae9f55adc7a4a59b25e..f696a08618d869556b9eb089f4414fd2510af3e0 100644 --- a/error_manager/error_code.json +++ b/error_manager/error_code.json @@ -2090,6 +2090,17 @@ "Solution": "Ensure that the NPU card is normal and entering environment variables 'export HCCL_INTRA_ROCE_ENABLE=1'." } }, + { + "errClass": "HCCL Errors", + "errTitle": "Resource_Error_Insufficient_Device_Memory", + "ErrCode": "EI0011", + "ErrMessage": "Failed to allocate [%s] bytes of NPU memory.", + "Arglist": "memory_size", + "suggestion": { + "Possible Cause": "Allocation failure due to insufficient NPU memory.", + "Solution": "Stop unnecessary processes and ensure the required memory is available." + } + }, { "errClass": "HCCP Errors", "errTitle": "HCCP_Process_Initialization_Failure", diff --git a/error_manager/error_manager.cc b/error_manager/error_manager.cc index 916e0c07fc35b2c2ac602cebda4dedc5218c95da..32763c1c43ccee1a98bf7e277b1dad3aba8be99b 100644 --- a/error_manager/error_manager.cc +++ b/error_manager/error_manager.cc @@ -14,7 +14,7 @@ #include #include #include "mmpa/mmpa_api.h" -#include "toolchain/dlog_pub.h" +#include "dlog_pub.h" #include "graph/def_types.h" #include "base/err_msg.h" #include "common/util/error_manager/error_manager.h" diff --git a/inc/common/ge_common/debug/ge_log.h b/inc/common/ge_common/debug/ge_log.h index 2a9358f329f1689af65e89a645753e175326938f..f5d932294d35ab039ca1c12f393522c153f04b12 100644 --- a/inc/common/ge_common/debug/ge_log.h +++ b/inc/common/ge_common/debug/ge_log.h @@ -17,7 +17,7 @@ #include "common/ge_common/ge_inner_error_codes.h" #include "common/util/error_manager/error_manager.h" #include "base/err_msg.h" -#include "toolchain/dlog_pub.h" +#include "dlog_pub.h" #ifdef __GNUC__ #include #include diff --git a/scripts/package/common/__init__.py b/scripts/package/common/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d5deb7c38eee592f57359ae8deb64a68769b46ea --- /dev/null +++ b/scripts/package/common/__init__.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- \ No newline at end of file diff --git a/scripts/package/common/cfg/path.cfg b/scripts/package/common/cfg/path.cfg new file mode 100644 index 0000000000000000000000000000000000000000..4e87f6e8ea9cedb8480cae16fd2d78cd5e1c9204 --- /dev/null +++ b/scripts/package/common/cfg/path.cfg @@ -0,0 +1,2 @@ +CUSTOM_DATA_PATH=$HOME/Ascend/latest/data/ +CUSTOM_CONF_PATH=$HOME/Ascend/latest/conf/ diff --git a/scripts/package/common/py/__init__.py b/scripts/package/common/py/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d5deb7c38eee592f57359ae8deb64a68769b46ea --- /dev/null +++ b/scripts/package/common/py/__init__.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- \ No newline at end of file diff --git a/scripts/package/common/py/filelist.py b/scripts/package/common/py/filelist.py new file mode 100644 index 0000000000000000000000000000000000000000..f2fbcbf2f3f2299a0cf89e2de3841c9135f2bf6f --- /dev/null +++ b/scripts/package/common/py/filelist.py @@ -0,0 +1,512 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +"""filelist相关类。""" + +import itertools +import os +from enum import IntEnum +from collections import Counter +from functools import partial +from itertools import chain, repeat +from operator import and_, attrgetter, contains, itemgetter, lt, methodcaller, ne, not_ +from typing import Callable, Iterator, List, NamedTuple, Set, Tuple + +from .utils.pkg_utils import (TOP_DIR, FilelistError, GenerateFilelistError, + conditional_apply, pairwise, swap_args, config_feature_to_string) +from .utils.funcbase import (any_, constant, dispatch, identity, invoke, pipe, side_effect, star_apply) +from .utils.comm_log import CommLog + + +class FileItem(NamedTuple): + """文件条目""" + module: str + operation: str + relative_path_in_pkg: str + relative_install_path: str + is_in_docker: str + permission: str + owner_group: str + install_type: str + softlink: List[str] + feature: Set[str] + is_common_path: str + configurable: str + hash_value: str + block: str + pkg_inner_softlink: List[str] + chip: Set[str] + is_dir: bool + + +def create_file_item(*args, **kwargs) -> FileItem: + """创建文件条目。""" + file_item = FileItem(*args, **kwargs) + + if not isinstance(file_item.feature, set): + raise TypeError('The feature parameter should be a set.') + if not isinstance(file_item.chip, set): + raise TypeError('The chip parameter should be a set.') + if not isinstance(file_item.softlink, list): + raise TypeError('The softlink parameter should be a list.') + if not isinstance(file_item.pkg_inner_softlink, list): + raise TypeError('The pkg_inner_softlink parameter should be a list.') + + return file_item + + +# 文件列表 +FileList = List[FileItem] + + +def soft_links_to_string(soft_links: List[str]) -> str: + """软链接转换为字符串。""" + if not soft_links: + return 'NA' + return ';'.join(soft_links) + + +def file_item_to_string(item: FileItem) -> str: + """文件条目转换为字符串。""" + return ','.join([ + item.module, item.operation, item.relative_path_in_pkg, item.relative_install_path, + item.is_in_docker, item.permission, item.owner_group, item.install_type, + soft_links_to_string(item.softlink), config_feature_to_string(item.feature), + item.is_common_path, item.configurable, item.hash_value, item.block, + soft_links_to_string(item.pkg_inner_softlink), config_feature_to_string(item.chip) + ]) + + +def get_filelist_header_string() -> str: + """获取文件列表表头。""" + return ','.join([ + 'module', 'operation', 'relative_path_in_pkg', 'relative_install_path', + 'is_in_docker', 'permission', 'owner:group', 'install_type', + 'softlink', 'feature', 'is_common_path', 'configurable', 'hash', + 'block', 'pkg_inner_softlink', 'chip' + ]) + + +def get_soft_links_not_in_common_paths(filelist: FileList, target_env: str) -> Iterator[List[str]]: + for file_item_t in filelist: + if file_item_t.relative_install_path.startswith(target_env): + for softlink in file_item_t.softlink: + if not softlink.startswith(target_env): + yield softlink + + +def fill_is_common_path(filelist: FileList, target_env: str) -> Iterator[FileItem]: + """填充文件条目中是否为公共目录字段。""" + soft_links = set(get_soft_links_not_in_common_paths(filelist, target_env)) + for file_item in filelist: + if file_item.relative_install_path.startswith(target_env): + yield file_item._replace(is_common_path='Y') + else: + is_soft_links_prefix = map( + methodcaller('startswith', f'{file_item.relative_install_path}/'), soft_links + ) + if any(is_soft_links_prefix): + yield file_item._replace(is_common_path='YY') + else: + yield file_item + + +def is_relative_install_path(path: str) -> bool: + """是否为相对路径。""" + if path.startswith('/'): + return False + return True + + +def is_specific_operations(file_item: FileItem, operations: List[str]) -> bool: + """是否为特定的操作类型。""" + if file_item.operation in operations: + return True + return False + + +def is_specific_install_type(file_item: FileItem, install_types: Set[str]) -> bool: + """是否为特定的安装类型。""" + item_install_types = set(file_item.install_type.split(';')) + if 'all' in item_install_types: + return True + if item_install_types & install_types: + return True + return False + + +def get_install_path_dirs(install_path: str) -> Iterator[str]: + """获取安装路径父目录。""" + install_path = os.path.dirname(install_path) + while install_path not in ('', '/'): + yield install_path + install_path = os.path.dirname(install_path) + + +def get_missing_dir_set(filelist: FileList) -> Set[str]: + """获取缺失目录集合。 + + 文件列表可能出现某一级目录缺失情况。 + 如配置了file_info:aaa/bbb/ccc.txt,但只配置了dir_info:aaa, + 那么缺失dir_info:aaa/bbb + """ + parent_dirs: Set[str] = invoke( + pipe( + dispatch( + pipe( + partial( + filter, + partial(is_specific_operations, operations={'copy', 'copy_entity'}), + ), + partial(map, attrgetter('relative_install_path')), + partial(filter, is_relative_install_path), + set, + partial(map, get_install_path_dirs), + chain.from_iterable, + ), + pipe( + partial(map, attrgetter('softlink')), + chain.from_iterable, + partial( + filter, + pipe( + dispatch( + bool, + is_relative_install_path, + partial(ne, 'NA'), + ), + all + ) + ), + set, + partial(map, get_install_path_dirs), + chain.from_iterable, + ), + pipe( + partial(map, attrgetter('pkg_inner_softlink')), + chain.from_iterable, + partial( + filter, + pipe( + dispatch( + bool, + partial(ne, 'NA'), + ), + all + ) + ), + set, + partial(map, get_install_path_dirs), + chain.from_iterable, + ), + ), + chain.from_iterable, + set, + ), + filelist + ) + mkdir_installs: Set[str] = { + file_item.relative_install_path + for file_item in filter( + partial(is_specific_operations, operations={'mkdir'}), + filelist + ) + if is_relative_install_path(file_item.relative_install_path) + } + + mkdir_parent_dirs: Set[str] = set( + itertools.chain.from_iterable( + map(get_install_path_dirs, mkdir_installs) + ) + ) + + missing_dir_set = sorted((parent_dirs | mkdir_parent_dirs) - mkdir_installs) + return set(missing_dir_set) + + +def print_missing_dir_set(missing_dir_set: Set[str], in_msg: str = None) -> Set[str]: + """打印缺失目录集合。""" + if in_msg: + tail_msg = f' {in_msg}' + else: + tail_msg = '' + for path in sorted(missing_dir_set): + CommLog.cilog_error(f'missing dir info path "{path}"{tail_msg}') + return missing_dir_set + + +def print_unsafe_paths(unsafe_paths: Tuple[str, ...]) -> Tuple[str, ...]: + """打印非安全路径。""" + for path in unsafe_paths: + CommLog.cilog_error(f'unsafe path "{path}" in move scene.') + return unsafe_paths + + +# 获取filelist中所有的特性集合 +get_features_in_filelist = pipe( + partial(map, attrgetter('feature')), + chain.from_iterable, # 展开集合序列为元素序列 + set, # 去重 + partial(filter, partial(ne, 'comm')), # 排除comm特性 + set, +) + +# 获取filelist中所有的芯片集合 +get_chips_in_filelist = pipe( + partial(map, attrgetter('chip')), + chain.from_iterable, # 展开集合序列为元素序列 + set, # 去重 +) + + +def check_features_in_filelist(features: Set[str], filelist: FileList) -> Set[str]: + """检查文件列表中特性配置目录规范。""" + return invoke( + pipe( + # 过滤指定features的file_item + partial( + filter, + pipe(attrgetter('feature'), partial(and_, features), bool) + ), + list, + get_missing_dir_set, + partial(print_missing_dir_set, in_msg=f'in features {features}'), + ), + filelist + ) + + +def check_chip_in_filelist(chip: str, filelist: FileList) -> Set[str]: + """检查文件列表中芯片配置目录规范。""" + return invoke( + pipe( + # 过滤指定chip的file_item + partial( + filter, + any_( + pipe( + attrgetter('chip'), not_ + ), # 没有配置chip + pipe( + attrgetter('chip'), partial(swap_args(contains), chip), bool + ), # 配置了指定chip + ), + ), + list, + get_missing_dir_set, + partial(print_missing_dir_set, in_msg=f'in chip {chip}'), + ), + filelist + ) + + +check_filelist_features = any_( + pipe( + dispatch( + pipe( + get_features_in_filelist, + # 对于每个feature,与comm组成一个set + partial(map, lambda x: {x, 'comm'}), + # 此时为feature集合序列 + ), + repeat, # 重复filelist + ), + tuple, + star_apply(zip), + # 此时为元组序列,元组的第1个元素是过滤的feature集合,第2个元素是filelist + partial(itertools.starmap, check_features_in_filelist), + # 此时为集合序列;合并为一个集合 + chain.from_iterable, + set, + ), + pipe( + dispatch( + get_chips_in_filelist, + repeat, # 重复filelist + ), + tuple, + star_apply(zip), + # 此时为元组序列,元组的第1个元素是chip集合,第2个元素是filelist + partial(itertools.starmap, check_chip_in_filelist), + # 此时为集合序列;合并为一个集合 + chain.from_iterable, + set, + ) +) + + +# 检查move是否安全,是否存在同一个源路径被mv多次 +check_move_safe = pipe( + partial( + filter, + partial(is_specific_operations, operations={'copy', 'copy_entity', 'move'}), + ), + partial(map, attrgetter('relative_path_in_pkg')), + Counter, + methodcaller('items'), + partial(filter, pipe(itemgetter(1), partial(lt, 1))), + partial(map, itemgetter(0)), + tuple, + print_unsafe_paths, +) + + +def check_filelist(filelist: FileList, check_features: bool, check_move: bool): + """检查文件列表是否符合规范。""" + if check_features: + check_features_func = check_filelist_features + else: + check_features_func = constant(set()) + + if check_move: + check_move_func = check_move_safe + else: + check_move_func = constant(tuple()) + + # 此处使用any_,短路部分报错 + check_func = any_( + pipe( + get_missing_dir_set, + print_missing_dir_set, + ), + pipe( + partial(filter, partial(is_specific_install_type, install_types={'run'})), + list, + get_missing_dir_set, + partial(print_missing_dir_set, in_msg='in run install type'), + ), + check_features_func, + check_move_func, + ) + missing = check_func(filelist) + + if missing: + raise FilelistError() + + +def get_common_path(args: List[str]) -> str: + """公共路径前缀。""" + try: + return os.path.commonpath(args) + except ValueError: + return '' + + +class FileItemRelation(IntEnum): + """文件条目之间的关系。""" + NOT_NESTED = 0 # 不是嵌套文件 + NESTED = 1 # 嵌套文件 + SAME = 2 # 相同文件 + + +def is_nested_file_item(item: FileItem, base_item: FileItem) -> FileItemRelation: + """是否为嵌套的文件。""" + if base_item is None: + return FileItemRelation.NOT_NESTED + + if item == base_item: + return FileItemRelation.SAME + + install_path = item.relative_install_path + base_install_path = base_item.relative_install_path + + common_install_path = get_common_path([install_path, base_install_path]) + if common_install_path != base_install_path: + return FileItemRelation.NOT_NESTED + + pkg_path = item.relative_path_in_pkg + base_pkg_path = base_item.relative_path_in_pkg + + install_rel_path = os.path.relpath(install_path, base_install_path) + pkg_rel_path = os.path.relpath(pkg_path, base_pkg_path) + if install_rel_path != pkg_rel_path: + # 确保打包与安装相对路径一致 + raise FilelistError(f'nested paths {item} and {base_item} are illegal.') + return FileItemRelation.NESTED + + +def found_nested_file_item(item: FileItem, base_item: FileItem): + """发现嵌套元素。""" + raise FilelistError(f'found nested paths {item} and {base_item}!') + + +def convert_nested_path_in_filelist(filelist: FileList): + """filelist中嵌套路径元素转为del。""" + pre_item = None + for item in filelist: + ret = is_nested_file_item(item, pre_item) + if ret == FileItemRelation.NESTED: + yield item._replace(operation='del') + elif any(( + ret == FileItemRelation.NOT_NESTED, + (ret == FileItemRelation.SAME and not item.is_dir) + )): + yield item + pre_item = item + + +# 检查文件列表中的嵌套路径。入参: filelist +check_nested_path_in_filelist = pipe( + partial(filter, partial(is_specific_operations, operations={'copy', 'copy_entity'})), + partial(sorted, key=attrgetter('relative_install_path')), + pairwise, + partial( + map, + conditional_apply(star_apply(is_nested_file_item), star_apply(found_nested_file_item)) + ), + list, +) + + +# 变换文件列表中嵌套路径。入参: filelist +transform_nested_path_in_filelist = pipe( + dispatch( + partial( + itertools.filterfalse, partial(is_specific_operations, operations={'copy'}) + ), + pipe( + partial(filter, partial(is_specific_operations, operations={'copy'})), + partial(sorted, key=attrgetter('relative_install_path')), + convert_nested_path_in_filelist + ), + ), + chain.from_iterable, + list, + side_effect(check_nested_path_in_filelist), +) + + +def generate_filelist(filelist: FileList, filename: str): + """生成文件列表文件。""" + content_list = list( + itertools.chain( + [get_filelist_header_string()], + [file_item_to_string(item) for item in filelist] + ) + ) + content = '\n'.join(content_list) + filepath = os.path.join(TOP_DIR, "build", filename) + try: + with open(filepath, 'w', encoding='utf-8') as file: + file.write(content) + # filelist.csv文件末尾补充一个换行符 + file.write('\n') + except OSError as ex: + raise GenerateFilelistError(filename) from ex + + +def get_transform_nested_path_func(parallel: bool) -> Callable[[FileList], FileList]: + """获取转换嵌套路径函数。""" + if parallel: + return transform_nested_path_in_filelist + return identity diff --git a/scripts/package/common/py/packer.py b/scripts/package/common/py/packer.py new file mode 100644 index 0000000000000000000000000000000000000000..af69a67ef9cbec05c9338d7c30bd8f9ff781774f --- /dev/null +++ b/scripts/package/common/py/packer.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +import shutil +from argparse import Namespace +from itertools import chain +from typing import Callable, Dict, List, NamedTuple, Optional, Tuple, Union + +from .utils.comm_log import CommLog + + +class PackageName: + """包名。""" + + def __init__(self, + package_attr, + args: Namespace, + version: str): + self.product_name = package_attr.get('product_name') + self.chip_name = args.chip_name or package_attr.get('chip_name') + self.suffix = args.suffix or package_attr.get('suffix') + self.func_name = get_func_name(args.func_name, package_attr) + self.chip_plat = package_attr.get('chip_plat') + self.deploy_type = package_attr.get('deploy_type') + self.version = version.lower() + self.not_in_name_list = args.not_in_name.split(",") + self.os_arch = args.os_arch + self.package_suffix = args.package_suffix + self.ext_name = args.ext_name + if args.pkg_name_style == 'underline': + self.name_sep = '_' + else: + self.name_sep = '-' + + def get_attribute(self, name: str) -> Optional[str]: + """获取属性。""" + if name in self.not_in_name_list: + return None + return getattr(self, name) + + def getvalue(self) -> str: + product_name = self.get_attribute('product_name') + chip_name = self.get_attribute('chip_name') + func_name = self.get_attribute('func_name') + version = self.get_attribute('version') + os_arch = self.get_attribute('os_arch') + chip_plat = self.get_attribute('chip_plat') + deploy_type = self.get_attribute('deploy_type') + ext_name = self.get_attribute('ext_name') + package_suffix = "debug" if self.package_suffix == "debug" else None + + region1 = "-".join(filter(None, [product_name, remove_ascend(chip_name), func_name])) + region2 = ".".join(filter(None, [version])) + region3 = "-".join(filter(None, [os_arch, chip_plat, deploy_type, package_suffix, ext_name])) + package_name = "_".join(filter(None, [region1, region2, region3])) + + return f"{package_name}.{self.suffix}" + + +class MakeselfPkgParams(NamedTuple): + """run包打包参数。""" + package_name: str + comments: str + cleanup: Optional[str] = None + + +def remove_ascend(text): + if text is None: + return None + text_lower = text.lower() + if "ascend" in text_lower: + return text_lower.replace("ascend", "") + return text_lower + + +def get_func_name(func_name: str, package_attr) -> str: + """获取包func_name。""" + return func_name or package_attr.get('func_name') + + +def get_compress_tool() -> str: + tools = ["pigz", "gzip", "bzip2", "xz"] + for tool in tools: + path = shutil.which(tool) + if path: + return "--" + tool + CommLog.cilog_error("The system does not come with a compression tool pre-installed." + "Please ensure at least one of the folllowing compression tools is available: %s", tools) + return "" + + +def get_compress_format() -> str: + tar_format = "gnu" + path = shutil.which("bsdtar") + if path: + tar_format = "ustar" + return tar_format + + +def compose_makeself_command(params: MakeselfPkgParams) -> str: + """组装makeself包打包命令。""" + + def get_cleanup_commands() -> List[str]: + if params.cleanup: + return ['--cleanup', params.cleanup] + return [] + + compress_tool = get_compress_tool() + tar_format = get_compress_format() + commands = chain( + [ + compress_tool, '--complevel', '4', + '--nomd5', '--sha256', '--nooverwrite', '--chown', '--tar-format', tar_format, + '--tar-extra', '--numeric-owner', '--tar-quietly' + ], + get_cleanup_commands(), + ['./', params.package_name, params.comments] + ) + + command = ' '.join(commands) + return command + + +def create_makeself_pkg_params_factory(package_name: str, + comments: str + ) -> Callable[[Dict], MakeselfPkgParams]: + """创建Makeself打包参数工厂。""" + + def create_makeself_pkg_params(package_attr: Dict) -> MakeselfPkgParams: + """创建Makeself打包参数。""" + cleanup = package_attr.get('cleanup') + params = MakeselfPkgParams( + package_name=package_name, + comments=comments, + cleanup=cleanup, + ) + + return params + + return create_makeself_pkg_params + + +def create_run_package_command(params: MakeselfPkgParams + ) -> Tuple[Optional[str], Optional[str]]: + """ + 功能描述: 组装打run包命令 + 返回值: command + """ + return compose_makeself_command(params), None diff --git a/scripts/package/common/py/pkg_parser.py b/scripts/package/common/py/pkg_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..b5d336f7f924cb5f3b60c39899cbae7450db4c33 --- /dev/null +++ b/scripts/package/common/py/pkg_parser.py @@ -0,0 +1,1087 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +import copy +import glob +import hashlib +import itertools +import re +import xml.etree.ElementTree as ET +import os +import sys +from argparse import Namespace +from functools import partial +from io import StringIO +from itertools import chain +from operator import attrgetter, itemgetter, methodcaller +from typing import ( + Any, Callable, Dict, Iterable, Iterator, List, NamedTuple, Optional, Set, Tuple, Union +) + +from .utils import pkg_utils +from .filelist import FileItem, FileList, fill_is_common_path +from .utils.pkg_utils import ( + ContainAsteriskError, FAIL, BLOCK_CONFIG_PATH, + BlockConfigError, EnvNotSupported, IllegalVersionDir, PackageError, + ParseOsArchError, config_feature_to_set, + flatten, star_pipe, merge_dict, yield_if +) +from .utils.funcbase import constant, dispatch, invoke, pipe, star_apply +from .utils.comm_log import CommLog +from .version_info import ( + VersionInfo, VersionXml, VersionFormatNotMatch, is_multi_version +) + +# 环境变量字典 +EnvDict = Dict[str, str] + +# 文件信息 +FileInfo = Dict[str, str] + +# 包属性 +PackageAttr = Dict[str, Union[str, bool]] + +# 生成信息 +GenerateInfo = Dict[str, str] + + +class ParseOption(NamedTuple): + """解析参数。""" + os_arch: Optional[str] + pkg_version: Optional[str] + build_type: Optional[str] + package_check: bool + ext_name: str = '' + + +def parse_os_arch(os_arch: str) -> Tuple[str, str, str]: + """解析系统和架构。""" + match = re.match("^([a-z]+)(\\d+(\\.\\d+)*)?[.-]?(\\S*)", os_arch) + if match: + os_name = match.group(1) + os_ver = match.group(2) + if match.group(4): + arch = match.group(4) + else: + # 如果os_arch中没有配置ARCH,ARCH默认值为aarch64 + arch = 'aarch64' + + return os_name, os_ver, arch + + raise ParseOsArchError() + + +def replace_env(env_dict: EnvDict, in_str: str): + """替换环境变量为实际值。""" + env_list = re.findall(".*?\\$\\((.*?)\\).*?", in_str) + for env in env_list: + if env == 'FILE': + continue + if env in env_dict: + if env_dict[env] is not None: + in_str = in_str.replace(f"$({env})", env_dict[env]) + else: + in_str = in_str.replace(f"$({env})", '') + else: + raise EnvNotSupported(f"Error: {env} not supported.") + return in_str + + +class ParseEnv(NamedTuple): + """解析上下文环境。""" + env_dict: EnvDict + parse_option: ParseOption + delivery_dir: str + top_dir: str + + +class BlockElement(NamedTuple): + """块配置。""" + name: str + block_conf_path: str + dst_path: str + chips: Set[str] + features: Set[str] + attrs: Dict[str, str] + + +# BlockElement直接透传给LoadedBlockElement的参数列表 +BLOCK_ELEMENT_PASS_THROUGH_ARGS = ['dst_path', 'chips', 'features', 'attrs'] + + +class LoadedBlockElement(NamedTuple): + """加载后的块配置。""" + root_ele: ET.Element + use_move: bool + dst_path: str + chips: Set[str] + features: Set[str] + attrs: Dict[str, str] + + +class FileInfoParsedResult(NamedTuple): + """file_info元素解析结果。""" + file_info: FileInfo + move_infos: List[FileInfo] + dir_infos: List[Dict[str, str]] + expand_infos: List[Dict[str, str]] + + +class BlockConfig(NamedTuple): + """块配置。""" + + dir_install_list: List[Dict] + move_files: List[FileInfo] + expand_content_list: List[Dict] + package_content_list: List[Dict] + generate_infos: List[GenerateInfo] + + +class PackerConfig(NamedTuple): + """安装相关配置。""" + fill_is_common_path: Callable[[FileList], Iterator[FileItem]] + + +class XmlConfig(NamedTuple): + """安装xml配置。""" + default_config: Dict[str, str] + package_attr: PackageAttr + version_info: VersionInfo + blocks: List[BlockConfig] + version: str + version_xml: Optional[VersionXml] + packer_config: PackerConfig + + def _collect_list(self, list_name): + result = [] + for block in self.blocks: + result.extend(getattr(block, list_name)) + return result + + @property + def dir_install_list(self): + return self._collect_list('dir_install_list') + + @property + def move_content_list(self): + return self._collect_list('move_files') + + @property + def expand_content_list(self): + return self._collect_list('expand_content_list') + + @property + def package_content_list(self): + return self._collect_list('package_content_list') + + @property + def generate_infos(self) -> List[GenerateInfo]: + return self._collect_list('generate_infos') + + +# 默认包属性 +DEFAULT_PACKAGE_ATTR = { + 'gen_version_info': True, +} + + +def parse_package_info(package_info_ele: Optional[ET.Element]) -> Dict: + """解析package_info元素。""" + + def get_package_info_attrs(ele: ET.Element) -> Iterator[Tuple[str, Union[str, bool]]]: + # expand_asterisk: 展开配置中星号 + # parallel: 并行复制文件 + # parallel_limit: 限制并发数 + # package_check: 检查filelist.csv中配置目录是否完整 + # check_features: 检查filelist.csv中所有feature是否符合package_check + # gen_version_info: 是否生成version.info文件 + bool_attrs = ( + 'expand_asterisk', 'parallel', 'parallel_limit', 'package_check', 'check_features', + 'use_move', 'gen_version_info' + ) + bool_values = ('t', 'true', 'y', 'yes') + if ele.tag in bool_attrs: + if ele.text.lower() in bool_values: + yield ele.tag, True + else: + yield ele.tag, False + else: + yield ele.tag, ele.text + + if not package_info_ele: + return {} + + attr = dict( + chain.from_iterable(map(get_package_info_attrs, list(package_info_ele))) + ) + + return attr + + +def parse_package_attr_by_args(args: Namespace) -> Dict: + """通过命令行参数解析""" + + def pairs(): + if hasattr(args, 'chip_name') and args.chip_name: + yield 'chip_name', args.chip_name + if hasattr(args, 'suffix') and args.suffix: + yield 'suffix', args.suffix + if hasattr(args, 'func_name') and args.func_name: + yield 'func_name', args.func_name + + return dict(pairs()) + + +def parse_package_attr(root_ele: ET.Element, args: Namespace) -> Dict: + """通过根元素解析package_info元素。""" + package_info_ele = root_ele.find("package_info") + return merge_dict( + DEFAULT_PACKAGE_ATTR, + parse_package_info(package_info_ele), + parse_package_attr_by_args(args), + ) + + +def render_cann_version(a_ver: int, + b_ver: int, + c_ver: Optional[int], + d_ver: Optional[int], + e_ver: Optional[int], + f_ver: Optional[int]) -> str: + """渲染CANN版本号。""" + buffer = StringIO() + buffer.write('(') + buffer.write(f'({a_ver + 1} * 100000000) + ({b_ver + 1} * 1000000)') + if c_ver is not None: + buffer.write(f' + ({c_ver + 1} * 10000)') + if d_ver is not None: + buffer.write(f' + (({d_ver + 1} * 100) + 5000)') + if e_ver is not None: + buffer.write(f' + ({e_ver + 1} * 100)') + if f_ver is not None: + buffer.write(f' + {f_ver}') + buffer.write(')') + return buffer.getvalue() + + +def get_cann_version(version_dir: str) -> str: + """获取CANN版本号。""" + if not version_dir: + return "" + + release_pattern = re.compile(r'(\d+)\.(\d+)\.(\d+)', re.IGNORECASE) + matched = release_pattern.fullmatch(version_dir) + if matched: + return render_cann_version( + int(matched.group(1)), int(matched.group(2)), int(matched.group(3)), None, None, None + ) + + release_alpha_pattern = re.compile(r'(\d+)\.(\d+)\.(\d+)\.[a-z]*(\d+)', re.IGNORECASE) + matched = release_alpha_pattern.fullmatch(version_dir) + if matched: + return render_cann_version( + int(matched.group(1)), int(matched.group(2)), int(matched.group(3)), None, None, + int(matched.group(4)) + ) + + rc_pattern = re.compile(r'(\d+)\.(\d+)\.RC(\d+)', re.IGNORECASE) + matched = rc_pattern.fullmatch(version_dir) + if matched: + return render_cann_version( + int(matched.group(1)), int(matched.group(2)), None, int(matched.group(3)), None, None + ) + + test_pattern = re.compile(r'(\d+)\.(\d+)\.T(\d+)', re.IGNORECASE) + matched = test_pattern.fullmatch(version_dir) + if matched: + return render_cann_version( + int(matched.group(1)), int(matched.group(2)), None, None, int(matched.group(3)), None + ) + + alpha_pattern = re.compile(r'(\d+)\.(\d+)\.RC(\d+)\.[a-z]*(\d+)', re.IGNORECASE) + matched = alpha_pattern.fullmatch(version_dir) + if matched: + return render_cann_version( + int(matched.group(1)), int(matched.group(2)), None, int(matched.group(3)), None, + int(matched.group(4)) + ) + + cann_pattern = re.compile(r'CANN-(\d+)\.(\d+)', re.IGNORECASE) + matched = cann_pattern.fullmatch(version_dir) + if matched: + return render_cann_version( + int(matched.group(1)), int(matched.group(2)), None, None, None, None + ) + + raise IllegalVersionDir(version_dir) + + +def get_cann_version_info(name: str, version_dir: str) -> List[Tuple[str, str]]: + """获取CANN版本号信息。""" + version_info = [] + + # 删除字符串中的_VERSION + package_name = name[:-8] + + if not version_dir: + version_str = '0' + elif version_dir.startswith('CANN-'): + version_str = version_dir[5:] + else: + version_str = version_dir + + version_info.append((f'{package_name}_VERSION_STR', f'"{version_str}"')) + + version = get_cann_version(version_dir) + version_info.append((f'{package_name}_VERSION', version)) + + return version_info + + +def get_default_env_items() -> Iterator[Tuple[str, str]]: + """获取默认环境字典条目。""" + yield 'VERSION_DIR', '' + yield 'HOME', os.environ.get('HOME') + + +def get_env_items_by_version(version: Optional[str]) -> Iterator[Tuple[str, str]]: + """根据version获取环境字典条目。""" + if version: + yield 'ASCEND_VER', version + + version_parts = version.split('.') + for idx in range(1, len(version_parts) + 1): + yield f'CUR_VER[{idx}]', '.'.join(version_parts[:idx]) + yield 'CUR_VER', version + yield 'LOWER_CUR_VER', version.lower() + + +def get_env_items_by_version_dir(version_dir: Optional[str]) -> Iterator[Tuple[str, str]]: + """根据version_dir获取环境字典条目。""" + if version_dir: + yield 'VERSION_DIR', version_dir + + +def get_os_arch_default_env_items() -> Iterator[Tuple[str, str]]: + """获取系统相关默认环境字典条目。""" + yield 'OS_NAME', 'linux' + yield 'OS_VER', '' + yield 'ARM', 'aarch64' + yield 'TARGET_ENV', '$(TARGET_ENV)' + + +def get_env_items_by_os_arch(os_arch: str) -> Iterator[Tuple[str, str]]: + """根据os_arch获取环境字典条目。""" + if os_arch: + os_name, os_ver, arch = parse_os_arch(os_arch) + yield 'OS_NAME', os_name + yield 'OS_VER', os_ver + yield 'ARCH', arch + yield 'OS_ARCH', os_arch + if arch in ('arm', 'sw_64'): + yield 'ARM', arch + else: + yield 'ARM', 'aarch64' + yield 'TARGET_ENV', f"{arch}-linux" + else: + yield from get_os_arch_default_env_items() + + +def get_env_items_by_timestamp(timestamp: Optional[str]) -> Iterator[Tuple[str, str]]: + """根据timestamp获取环境字典条目。""" + if timestamp: + yield 'TIMESTAMP', timestamp + yield 'TIMESTAMP_NO', timestamp.replace('_', '') + else: + yield 'TIMESTAMP', '0' + yield 'TIMESTAMP_NO', '0' + + +def parse_env_dict(os_arch: str, + package_attr: PackageAttr, + version: Optional[str], + version_dir: Optional[str], + timestamp: Optional[str]) -> EnvDict: + """解析环境变量字典。""" + env_dict = dict( + chain( + get_default_env_items(), + yield_if(('ARCH', package_attr.get('default_arch')), itemgetter(1)), + get_env_items_by_os_arch(os_arch), + get_env_items_by_version(version), + get_env_items_by_version_dir(version_dir), + yield_if(('VERSION_DIR', version_dir), constant(version_dir)), + get_env_items_by_timestamp(timestamp), + ) + ) + + return env_dict + + +def get_timestamp(args: Namespace) -> Optional[str]: + """获取触发时间戳。""" + if 'tag' not in args: + return None + + tag = args.tag + if tag: + timestamp_re = r"\d{8}_\d{9}" + timestamp_list = re.findall(timestamp_re, tag) + if not timestamp_list: + raise PackageError("The {} format is incorrect.".format(tag)) + timestamp = timestamp_list[-1] + else: + timestamp = None + return timestamp + + +def extract_element_attrib(ele: ET.Element) -> Dict: + """提取元素属性。""" + return ele.attrib.copy() + + +def extract_generate_info_content(generate_info_ele: ET.Element, env_dict: EnvDict) -> Dict: + """提取生成信息内容。""" + file_content = { + sub_item.tag: replace_env(env_dict, sub_item.text) + for sub_item in list(generate_info_ele) + } + return { + 'content': file_content + } + + +def parse_generate_infos_by_loaded_block(loaded_block: LoadedBlockElement, + default_config: Dict[str, str], + env_dict: EnvDict) -> List[Dict]: + """根据根元素解析生成信息列表。""" + return invoke( + pipe( + partial( + map, pipe( + dispatch( + pipe( + extract_element_attrib, + partial(merge_dict, default_config), + partial(evaluate_info, loaded_block=loaded_block, env_dict=env_dict), + ), + partial(extract_generate_info_content, env_dict=env_dict), + ), + star_apply(merge_dict), + ) + ), + list, + ), + loaded_block.root_ele.findall('generate_info') + ) + + +def join_pkg_inner_softlink(link_str_list: List[str]) -> str: + """合并pkg_inner_softlink""" + path = "/".join(link_str_list) + return os.path.normpath(path) + + +def check_contain_asterisk(value: str) -> bool: + """检查串是否包含星号。""" + if '*' in value: + return True + return False + + +def check_value(value: str, + package_check: bool, + package_attr: PackageAttr): + """检查元素value属性。""" + if package_check and package_attr.get('suffix') == 'run': + if check_contain_asterisk(value): + raise ContainAsteriskError(value) + + +def get_dst_prefix(file_info: FileInfo, env: ParseEnv) -> str: + """获取文件的前缀。""" + return os.path.join(env.delivery_dir, file_info['dst_path']) + + +def get_dst_target(file_info: FileInfo, env: ParseEnv) -> str: + """获取文件的实际路径。""" + dst_prefix = get_dst_prefix(file_info, env) + return os.path.join(dst_prefix, os.path.basename(file_info.get('value'))) + + +def make_hash(filepath: str) -> str: + """计算文件的hash(sha256)值。""" + sha256_hash = hashlib.sha256() + with open(filepath, "rb") as file: + sha256_hash.update(file.read()) + + return sha256_hash.hexdigest() + + +def config_hash(parsed_result: FileInfoParsedResult, env: ParseEnv): + """配置hash值。""" + file_info = parsed_result.file_info + # 如果配置了configurable,需要计算文件的hash值 + if file_info and file_info['configurable'] == 'TRUE': + src_target = get_dst_target(file_info, env) + hash_value = make_hash(src_target) + file_info['hash'] = hash_value + return parsed_result + + +def apply_func(func: Callable[[str], str], + value: Union[List[str], Set[str], str] + ) -> Union[List[str], Set[str], str]: + """对一个字符串,或字符串序列,应用函数。""" + # 如:pkg_softlink列表 + if isinstance(value, list): + return list(map(func, value)) + # 如:feature集合 + if isinstance(value, set): + return set(map(func, value)) + return func(value) + + +REAL_PREFIX = 'real:' + + +def join_dst_path(base: str, other: str) -> str: + """联结dst_path。""" + if other.startswith('real:'): + other = other[len(REAL_PREFIX):] + return other + return os.path.join(base, other) + + +def evaluate_info(info: Dict[str, str], + loaded_block: LoadedBlockElement, + env_dict: EnvDict) -> Dict[str, str]: + """info元素求值。""" + dst_keys = ('dst_path',) + + replace_env_func = partial(replace_env, env_dict) + add_dst_path_func = partial(join_dst_path, loaded_block.dst_path) + + def upper_value(key: str, value: str) -> Tuple[str, str]: + if key == 'configurable': + return key, value.upper() + return key, value + + def add_dst_path(key: str, value: str) -> Tuple[str, str]: + if key in dst_keys: + return key, apply_func(add_dst_path_func, value) + return key, value + + def replace_pkg_inner_softlink(key: str, value: str) -> Tuple[str, str]: + if key == 'pkg_inner_softlink': + inner_softlink_new = [ + join_pkg_inner_softlink(link_str.split(':')) + for link_str in value.split(';') + if ':' not in link_str or link_str.split(':')[0] == loaded_block.dst_path + ] + if inner_softlink_new: + return key, ';'.join(inner_softlink_new) + return key, 'NA' + return key, value + + def merge_feature(key: str, value: str) -> Tuple[str, str]: + if key in ('chip', 'feature'): + config_features = config_feature_to_set(value, key) + return key, config_features | getattr(loaded_block, f'{key}s') + return key, value + + def eval_value(_key: str, value: str) -> str: + if value is not None: + return apply_func(replace_env_func, value) + + eval_value_func = star_pipe( + upper_value, add_dst_path, replace_pkg_inner_softlink, + merge_feature, eval_value, + ) + + return { + key: eval_value_func(key, value) + for key, value in + itertools.chain( + # 默认值配置 + [ + ('dst_path', ''), ('configurable', 'FALSE'), + ('chip', None), ('feature', None), ('pkg_feature', None), + ], + info.items() + ) + } + + +def parse_dir_info_elements(loaded_block: LoadedBlockElement, + default_config: Dict[str, str], + package_attr: PackageAttr, + env: ParseEnv) -> List[Dict[str, str]]: + """解析dir_info元素。""" + dir_info_elements: List[ET.Element] = loaded_block.root_ele.findall('dir_info') + dir_infos = [] + for item in dir_info_elements: + dir_config = default_config.copy() + dir_config.update(item.attrib) + dir_config['module'] = dir_config.get('value') + for sub_item in list(item): + dir_info = dir_config.copy() + dir_info.update(sub_item.attrib) + dir_info = evaluate_info(dir_info, loaded_block, env.env_dict) + check_value( + dir_info['value'], env.parse_option.package_check, package_attr + ) + dir_infos.append(dir_info) + + return dir_infos + + +def expand_dir(file_info: FileInfo, get_dst_target_func: Callable[[FileInfo], str]): + """ + 如果file_info中配置的路径是文件夹,需要展开到文件 + """ + file_info_list = [] + dir_info_list = [] + dst_target = get_dst_target_func(file_info) + + value_list = file_info.get('value').split('/') + target_name = value_list[-1] if value_list[-1] else value_list[-2] + + # 这里把当前目录也加入到dir_info_list中 + dir_info_copy = file_info.copy() + dir_info_copy['module'] = file_info.get('value') + dir_info_copy['value'] = os.path.join( + file_info.get('install_path', ''), target_name + ) + + # 子目录的权限按照xml中subdir_mod配置,如果没有配置subdir_mod按照install_mod配置 + subdir_mod = file_info.get("subdir_mod", None) + if subdir_mod is not None: + dir_info_copy['install_mod'] = subdir_mod + # 被展开的当前目录不需要设置softlink + dir_info_copy['install_softlink'] = 'NA' + dir_info_copy['pkg_inner_softlink'] = 'NA' + dir_info_list.append(dir_info_copy) + + for root, dirs, files in os.walk(dst_target, followlinks=True): + # 不同操作系统上,os.walk遍历的结果顺序会略有不同,这里按字母排序,保证不同系统一致 + dirs.sort() + files.sort() + + dirs_to_remove = [] + for name in dirs: + dirname = os.path.join(root, name) + # 如果是指向目录的软连接,则按照文件处理,无需在安装时创建目录,只需要卸载时删除就行 + if os.path.islink(dirname) and not need_dereference(file_info): + copy_file_info = create_file_info(dirname, dst_target, file_info, name, target_name) + # 被展开的子文件不需要设置softlink + copy_file_info['install_softlink'] = 'NA' + copy_file_info['pkg_inner_softlink'] = 'NA' + file_info_list.append(copy_file_info) + dirs_to_remove.append(name) + continue + relative_dirname = os.path.relpath(dirname, dst_target) + dir_info_copy = file_info.copy() + dir_info_copy['module'] = file_info.get('value') + dir_info_copy['value'] = os.path.join( + file_info.get('install_path', ''), target_name, relative_dirname + ) + # 被展开的子目录不需要设置softlink + dir_info_copy['install_softlink'] = 'NA' + dir_info_copy['pkg_inner_softlink'] = 'NA' + # 子目录的权限按照xml中subdir_mod配置,如果没有配置subdir_mod按照install_mod配置 + subdir_mod = file_info.get("subdir_mod", None) + if subdir_mod is not None: + dir_info_copy['install_mod'] = subdir_mod + dir_info_list.append(dir_info_copy) + for name in files: + filename = os.path.join(root, name) + copy_file_info = create_file_info(filename, dst_target, file_info, name, target_name) + file_info_list.append(copy_file_info) + + for name in dirs_to_remove: + dirs.remove(name) + return file_info_list, dir_info_list + + +def create_file_info(dirname, dst_target, file_info, name, target_name): + relative_filename = os.path.relpath(dirname, dst_target) + relative_dir_name = os.path.split(relative_filename)[0] + copy_file_info = file_info.copy() + copy_file_info['value'] = name + copy_file_info['src_path'] = os.path.join( + file_info['src_path'], file_info['value'], relative_dir_name + ) + copy_file_info['dst_path'] = os.path.join( + file_info['dst_path'], target_name, relative_dir_name + ) + copy_file_info['install_path'] = os.path.join( + file_info.get('install_path', ''), target_name, relative_dir_name + ) + return copy_file_info + + +def expand_file_info_asterisk(parsed_result: FileInfoParsedResult, + env: ParseEnv) -> Iterator[FileInfoParsedResult]: + """展开FileInfoParsedResult中的星号。""" + file_info = parsed_result.file_info + if check_contain_asterisk(file_info.get('value', '')): + dst_prefix = get_dst_prefix(file_info, env) + dst_targets = sorted(glob.glob(get_dst_target(file_info, env))) + if 'exclude' in file_info: + exclude = list(map(methodcaller('strip'), file_info['exclude'].split(';'))) + else: + exclude = [] + for dst_target in dst_targets: + value = os.path.relpath(dst_target, dst_prefix) + if value in exclude: + continue + new_file_info = file_info.copy() + new_file_info['value'] = value + if 'pkg_inner_softlink' in new_file_info: + # pkg_inner_softlink中的特殊变量$(FILE)替换为展开后的文件名 + pkg_inner_softlink = new_file_info['pkg_inner_softlink'] + new_file_info['pkg_inner_softlink'] = pkg_inner_softlink.replace( + '$(FILE)', os.path.basename(dst_target) + ) + yield parsed_result._replace(file_info=new_file_info) + else: + yield parsed_result + + +def trans_to_stream(item: Any) -> Iterator[Any]: + """转换为流。""" + yield item + + +def need_dereference(file_info: FileInfo) -> bool: + """是否需要解引用。""" + if 'dereference' in file_info: + return True + return False + + +def need_expand(file_info: FileInfo, get_dst_target_func: Callable[[FileInfo], str]) -> bool: + """是否需要展开子目录。""" + if file_info.get('entity') == 'true': + return False + dst_target = get_dst_target_func(file_info) + if os.path.isdir(dst_target): + if need_dereference(file_info): + return True + if os.path.islink(dst_target): + return False + return True + return False + + +def expand_file_info(parsed_result: FileInfoParsedResult, + use_move: bool, + get_dst_target_func: Callable[[FileInfo], str]) -> FileInfoParsedResult: + """展开FileInfoParsedResult中的目录。""" + file_info = parsed_result.file_info + if need_expand(file_info, get_dst_target_func): + # 如果当前是文件夹,需要展开计算 + expand_infos, dir_infos = expand_dir(file_info, get_dst_target_func) + # 实测发现,对于opp包,整体目录cp的安装速度要快于目录中各文件mv + # 可能的原因是,cp遍历目录的速度较快,并且目录中的文件都比较小。mv依赖shell迭代目录中的所有文件。 + return FileInfoParsedResult( + merge_dict(file_info, {'is_dir': True}), [], dir_infos, expand_infos + ) + + if use_move: + return FileInfoParsedResult( + {}, [file_info], parsed_result.dir_infos, parsed_result.expand_infos + ) + + return parsed_result + + +def trans_file_info_to_result(file_info: FileInfo) -> FileInfoParsedResult: + """file_info转换为FileInfoParsedResult。""" + return FileInfoParsedResult(file_info, [], [], []) + + +def parse_file_element(file_ele: ET.Element, + file_config: Dict[str, str], + loaded_block: LoadedBlockElement, + package_attr: PackageAttr, + env: ParseEnv) -> Iterator[FileInfoParsedResult]: + """解析file元素。""" + file_info = merge_dict(file_config, file_ele.attrib) + file_info = evaluate_info(file_info, loaded_block, env.env_dict) + + if package_attr.get('expand_asterisk', False): + expand_asterisk_func = partial(expand_file_info_asterisk, env=env) + else: + expand_asterisk_func = trans_to_stream + + if 'install_path' not in file_info: + file_info['install_path'] = '' + + trans_file_info_func = pipe( + trans_file_info_to_result, + expand_asterisk_func, + partial(map, partial(config_hash, env=env)), + partial( + map, + partial( + expand_file_info, + use_move=loaded_block.use_move, + get_dst_target_func=partial(get_dst_target, env=env) + ) + ), + ) + + yield from trans_file_info_func(file_info) + + +def parse_file_info_elements(loaded_block: LoadedBlockElement, + default_config: Dict[str, str], + package_attr: PackageAttr, + env: ParseEnv) -> Iterator[FileInfoParsedResult]: + """解析file_info元素。""" + file_info_elements: List[ET.Element] = loaded_block.root_ele.findall('file_info') + for file_info_ele in file_info_elements: + file_config = merge_dict( + default_config, + file_info_ele.attrib, + {'module': file_info_ele.attrib.get('value')} + ) + + for sub_item in list(file_info_ele): + yield from parse_file_element( + sub_item, file_config, loaded_block, package_attr, env + ) + + +def unique_infos(infos: Iterable) -> List[Dict[str, str]]: + """infos去重。""" + cache: Set[str] = set() + new_infos = [] + for info in infos: + if info['value'] in cache: + continue + cache.add(info['value']) + new_infos.append(info) + + return new_infos + + +def parse_block_config(loaded_block: LoadedBlockElement, + package_attr: PackageAttr, + parse_env: ParseEnv): + """解析块配置。""" + default_config = copy.copy(loaded_block.attrs) + default_config.update(loaded_block.root_ele.attrib) + + dir_infos = parse_dir_info_elements( + loaded_block, + default_config, + package_attr, + parse_env, + ) + file_info_results = list( + chain( + parse_file_info_elements( + loaded_block, + default_config, + package_attr, + parse_env, + ) + ) + ) + + generate_infos = parse_generate_infos_by_loaded_block( + loaded_block, default_config, parse_env.env_dict + ) + + return BlockConfig( + unique_infos( + itertools.chain(dir_infos, + flatten(result.dir_infos for result in file_info_results) + ) + ), + list(flatten(map(attrgetter('move_infos'), file_info_results))), + list(flatten(map(attrgetter('expand_infos'), file_info_results))), + [result.file_info for result in file_info_results if result.file_info], + generate_infos, + ) + + +def make_loaded_block_element(root_ele: ET.Element, + dst_path: str = '') -> LoadedBlockElement: + """创建加载后的块配置。""" + return LoadedBlockElement(root_ele, False, dst_path, set(), set(), {}) + + +def parse_block_element(block_ele: ET.Element, + block_info_attr: Dict[str, str]) -> BlockElement: + """解析单个块配置。""" + + def filter_attrs(attrs: Dict[str, str]) -> Dict[str, str]: + # block属性中过滤掉dst_path与block_conf_path + # dst_path由单独的参数传递 + # block中不需要block_conf_path + return { + key: value + for key, value in attrs.items() + if key not in ('dst_path', 'block_conf_path') + } + + def with_merged_attrs(attrs: Dict[str, str]) -> BlockElement: + name = attrs.get('name') + block_conf_path = attrs.get('block_conf_path') + + if not name: + raise BlockConfigError("block's name is not set!") + + if not block_conf_path: + raise BlockConfigError("block's conf_path is not set!") + + return BlockElement( + name=name, + block_conf_path=block_conf_path, + dst_path=attrs.get('dst_path', ''), + chips=config_feature_to_set(attrs.get('chip'), 'chip'), + features=config_feature_to_set(attrs.get('feature'), 'feature'), + attrs=filter_attrs(attrs) + ) + + return with_merged_attrs(merge_dict(block_info_attr, block_ele.attrib)) + + +def parse_block_info(block_info: ET.Element) -> List[BlockElement]: + """解析块配置。""" + def parse_block_elements(block_elements: List[ET.Element]) -> List[BlockElement]: + return [ + parse_block_element(block_ele, block_info.attrib) for block_ele in block_elements + ] + + return parse_block_elements(list(block_info)) + + +def get_block_filepath(block_element: BlockElement) -> str: + """获取块配置路径。""" + return os.path.join( + pkg_utils.TOP_SOURCE_DIR, BLOCK_CONFIG_PATH, block_element.block_conf_path, + f'{block_element.name}.xml' + ) + + +def load_block_element(package_attr: PackageAttr, + block_element: BlockElement) -> LoadedBlockElement: + """加载块配置。""" + + def with_filepath(block_xml: str): + if not os.path.exists(block_xml): + raise BlockConfigError(f"block's config xml {block_xml} does not exist!") + + try: + return LoadedBlockElement( + root_ele=ET.parse(block_xml).getroot(), + use_move=package_attr.get('use_move', False), + **{ + name: getattr(block_element, name) + for name in BLOCK_ELEMENT_PASS_THROUGH_ARGS + } + ) + except Exception: + raise BlockConfigError(f"dependent block configuration {block_xml} parse failed!") + + return with_filepath(get_block_filepath(block_element)) + + +def parse_blocks(root_ele: ET.Element, + package_attr: PackageAttr, + parse_env: ParseEnv) -> List[BlockConfig]: + """解析块列表。""" + return [ + parse_block_config( + loaded_block, package_attr, parse_env + ) + for loaded_block in itertools.chain( + [make_loaded_block_element(root_ele)], + map( + partial(load_block_element, package_attr), + chain.from_iterable( + map(parse_block_info, root_ele.findall("block_info")) + ) + ) + ) + ] + + +def read_version_info() -> Tuple[str, str]: + version_path = os.path.join(pkg_utils.TOP_DIR, "version.info") + with open(version_path, 'r') as file: + line1 = file.readline().strip() + line2 = file.readline().strip() + version = line1.split("=")[1] + version_dir = line2.split("=")[1] + m = re.match(r'[.a-zA-Z0-9]+$', version) + if not m: + raise VersionFormatNotMatch() + + return version, version_dir + + +def parse_xml_config(filepath: str, + delivery_dir: str, + parse_option: ParseOption, + args: Namespace) -> XmlConfig: + """解析打包xml配置。""" + try: + tree = ET.parse(filepath) + xml_root = tree.getroot() + except ET.ParseError as ex: + CommLog.cilog_error("xml parse %s failed: %s!", filepath, ex) + sys.exit(FAIL) + + default_config = xml_root.attrib.copy() + + package_attr = parse_package_attr(xml_root, args) + version, version_dir = read_version_info() + if args.disable_multi_version: + version_dir = None + timestamp = get_timestamp(args) + try: + env_dict = parse_env_dict( + parse_option.os_arch, package_attr, version, version_dir, timestamp + ) + except ParseOsArchError: + CommLog.cilog_error( + "os_arch %s is not correctly configured: %s!", + parse_option.os_arch, filepath + ) + sys.exit(FAIL) + + parse_env = ParseEnv( + env_dict, parse_option, delivery_dir, pkg_utils.TOP_SOURCE_DIR + ) + + blocks = parse_blocks( + xml_root, package_attr, parse_env + ) + + if is_multi_version(version_dir): + fill_is_common_path_func = partial( + fill_is_common_path, target_env=env_dict.get('TARGET_ENV') + ) + else: + fill_is_common_path_func = iter + + return XmlConfig( + default_config, package_attr, None, blocks, version, None, + PackerConfig(fill_is_common_path_func) + ) diff --git a/scripts/package/common/py/utils/comm_log.py b/scripts/package/common/py/utils/comm_log.py new file mode 100644 index 0000000000000000000000000000000000000000..f2c7eb293b151d11e90f8457fd18ee6c1ac5041a --- /dev/null +++ b/scripts/package/common/py/utils/comm_log.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +import time +import inspect +import logging + +logging.basicConfig(format='[%(asctime)s] [%(levelname)s] [%(pathname)s] [line:%(lineno)d] %(message)s', + level=logging.INFO) + + +class CommLog: + @staticmethod + def cilog_get_timestamp(): + return time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()) + + @staticmethod + def cilog_print_element(cilog_element): + print("["+cilog_element+"]", end=' ') + return + + @staticmethod + def cilog_logmsg(log_level, filename, line_no, log_msg, *log_paras): + log_timestamp = CommLog.cilog_get_timestamp() + CommLog.cilog_print_element(log_timestamp) + CommLog.cilog_print_element(log_level) + CommLog.cilog_print_element(filename) + CommLog.cilog_print_element(str(line_no)) + print(log_msg % log_paras[0]) + return + + @staticmethod + def cilog_error(log_msg, *log_paras): + frame = inspect.currentframe().f_back + line_no = frame.f_lineno + filename = frame.f_code.co_filename + CommLog.cilog_logmsg("ERROR", filename, line_no, log_msg, log_paras) + return + + @staticmethod + def cilog_warning(log_msg, *log_paras): + frame = inspect.currentframe().f_back + line_no = frame.f_lineno + filename = frame.f_code.co_filename + CommLog.cilog_logmsg("WARNING", filename, line_no, log_msg, log_paras) + return + + @staticmethod + def cilog_info(log_msg, *log_paras): + frame = inspect.currentframe().f_back + line_no = frame.f_lineno + filename = frame.f_code.co_filename + CommLog.cilog_logmsg("INFO", filename, line_no, log_msg, log_paras) + return diff --git a/scripts/package/common/py/utils/funcbase.py b/scripts/package/common/py/utils/funcbase.py new file mode 100644 index 0000000000000000000000000000000000000000..77c8c0740cb4db77a427ef1ad3b43cd33ca1278d --- /dev/null +++ b/scripts/package/common/py/utils/funcbase.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +"""函数基础库。""" + +import operator +from typing import Callable, Iterator, TypeVar + + +A = TypeVar('A') + + +def constant(value: A) -> Callable[..., A]: + """常量值。""" + def constant_inner(*_args, **_kwargs) -> A: + return value + + return constant_inner + + +def dispatch(*funcs): + """分派应用。""" + def dispatch_inner(*args, **kwargs) -> Iterator: + return (func(*args, **kwargs) for func in funcs) + + return dispatch_inner + + +def pipe(*funcs): + """串联多个函数。""" + def pipe_func(*args, **k_args): + result = funcs[0](*args, **k_args) + for func in funcs[1:]: + result = func(result) + return result + + return pipe_func + + +def identity(value: A) -> A: + """同一。""" + return value + + +def invoke(func, *args, **kwargs): + """调用。""" + return func(*args, **kwargs) + + +def side_effect(*funcs): + """调用函数,产生副作用,但不影响管道结果。""" + def side_effect_func(arg): + for func in funcs: + # 不保留结果 + func(arg) + return arg + + return side_effect_func + + +def star_apply(func): + """列表展开再应用。""" + def star_apply_func(arg): + return func(*arg) + + return star_apply_func + + +def any_(*funcs) -> Callable: + """高阶any。 + 注意,any有短路效果。""" + return pipe( + dispatch(*funcs), + any, + ) + + +def not_(func) -> Callable: + """高阶not。""" + return pipe(func, operator.not_) diff --git a/scripts/package/common/py/utils/pkg_utils.py b/scripts/package/common/py/utils/pkg_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..c6107dfff700de434f6a16e1a82d724461532b3a --- /dev/null +++ b/scripts/package/common/py/utils/pkg_utils.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +"""基础构件。""" + +import os +from functools import partial +from itertools import chain, tee +from operator import methodcaller +from pathlib import Path +from typing import Callable, Dict, Iterator, List, Optional, TypeVar, Set + +TOP_DIR = str(Path(__file__).resolve().parents[5]) +TOP_SOURCE_DIR = TOP_DIR + '/scripts/' +DELIVERY_PATH = "build/_CPack_Packages/makeself_staging" +CONFIG_SCRIPT_PATH = 'package' +BLOCK_CONFIG_PATH = 'package/module' + +SUCCESS = 0 +FAIL = -1 + + +A = TypeVar('A') + + +class PackageError(Exception): + """打包异常基类。""" + + +class PackageConfigError(PackageError): + """打包配置错误异常。""" + + +class BlockConfigError(PackageError): + """块配置错误异常。""" + + +class ParseOsArchError(PackageError): + """解析os_arch失败异常。""" + + +class EnvNotSupported(PackageError): + """环境变量不支持异常。""" + + +class ContainAsteriskError(PackageError): + """包含星号异常。""" + + def __init__(self, value: str): + super().__init__() + self.value = value + + +class FilelistError(PackageError): + """文件列表异常。""" + + +class UnknownOperateTypeError(PackageError): + """未知的操作类型。""" + + +class PackageNameEmptyError(PackageError): + """包名为空错误。""" + + +class GenerateFilelistError(PackageError): + """生成文件列表文件异常。""" + + def __init__(self, filename: str): + super().__init__() + self.filename = filename + + +class IllegalVersionDir(PackageError): + """version_dir配置错误。""" + + +class CompressError(PackageError): + """打包错误。""" + + def __init__(self, package_name: Optional[str]): + super().__init__(package_name) + self.package_name = package_name + + +def flatten(list_of_lists): + """Flatten one level of nesting""" + return chain.from_iterable(list_of_lists) + + +def merge_dict(base: Dict, *news: Dict): + """合并两个字典。""" + result = base.copy() + for new in news: + result.update(new) + return result + + +def star_pipe(*funcs): + """串联多个函数。解包结果。""" + def pipe_func(*args, **k_args): + result = funcs[0](*args, **k_args) + for func in funcs[1:]: + # 解包元组或列表结果 + result = func(*result) + return result + + return pipe_func + + +def swap_args(func): + """交换函数前两个参数。""" + def inner(fst, snd, *args, **k_args): + return func(snd, fst, *args, **k_args) + return inner + + +def conditional_apply(predicate, func): + """条件下应用函数。""" + def conditional_apply_func(arg): + if predicate(arg): + return func(arg) + return arg + + return conditional_apply_func + + +def pairwise(iterable): + """s -> (s0,s1), (s1,s2), (s2, s3), ...""" + a, b = tee(iterable) + next(b, None) + return zip(a, b) + + +def path_join(base: Optional, *others: str) -> Optional: + """路径联合。""" + if base is None: + return None + return os.path.join(base, *others) + + +def yield_if(data, predicate: Callable) -> Iterator: + """条件满足则产生。""" + if predicate(data): + yield data + + +def config_feature_to_set(feature_str: str, feature_type: str = 'feature') -> Set[str]: + """配置feature转换为集合。""" + if feature_str is None: + return set() + + if isinstance(feature_str, set): + return feature_str + + if feature_str == '': + raise PackageConfigError(f"Not allow to config {feature_type} empty.") + + features = set(feature_str.split(';')) + if 'all' in features: + raise PackageConfigError(f"Not allow to config {feature_type} all.") + return features + + +def config_feature_to_string(features: Set[str]) -> str: + """配置feature集合转换为字符串。""" + if not features: + return 'all' + return ';'.join(sorted(features)) diff --git a/scripts/package/common/py/version_info.py b/scripts/package/common/py/version_info.py new file mode 100644 index 0000000000000000000000000000000000000000..6698457ef7e55e16e9c3aa2ed9d8223466f1666a --- /dev/null +++ b/scripts/package/common/py/version_info.py @@ -0,0 +1,433 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +import os +import re +import sys +import xml.etree.ElementTree as ET +from functools import total_ordering +from pathlib import Path +from typing import Dict, List, NamedTuple, Optional, Tuple, Union +from .utils.comm_log import CommLog + + +class VersionInfoError(Exception): + """版本信息异常基类。""" + + +class VersionFormatNotMatch(VersionInfoError): + """版本格式未匹配。""" + + +class IntervalFormatNotMatch(VersionInfoError): + """区间格式未匹配。""" + + +class DuplicatedPkgConfig(VersionInfoError): + """解析版本配置失败。重复的包配置。""" + + def __init__(self, pkg_name): + super().__init__(pkg_name) + self.pkg_name = pkg_name + + +class ParseVersionFailed(VersionInfoError): + """解析版本失败。""" + + +class CollectRequiresFailed(VersionInfoError): + """收集包需求失败。""" + + def __init__(self, pkg_name, version_str, msg): + super().__init__(pkg_name, version_str, msg) + self.pkg_name = pkg_name + self.version_str = version_str + self.msg = msg + + +@total_ordering +class Version: + """版本号。""" + + def __init__(self, version): + self.version = version + + @classmethod + def match(cls, input_str): + """输入字符串是否匹配版本号模式。""" + m = re.match(r'[.a-zA-Z0-9]+$', input_str) + return bool(m) + + @classmethod + def parse(cls, input_str): + """解析版本号。""" + if not cls.match(input_str): + raise VersionFormatNotMatch() + + return cls(input_str) + + @classmethod + def try_convert_to_int_list(cls, str_list): + """尝试转换为int数组。""" + for idx, item in enumerate(str_list): + try: + int_item = int(item) + str_list[idx] = int_item + except ValueError: + pass + + def to_required_list(self): + """转换为版本需求字符串列表。""" + return [self.version] + + def __eq__(self, other): + """等于。""" + if not isinstance(other, self.__class__): + return False + return self.version == other.version + + def __lt__(self, other): + """小于。""" + if not isinstance(other, self.__class__): + return True + + self_list = self.version.split('.') + other_list = other.version.split('.') + + self.try_convert_to_int_list(self_list) + self.try_convert_to_int_list(other_list) + + self_tuple = tuple(self_list) + other_tuple = tuple(other_list) + + return self_tuple < other_tuple + + def __str__(self): + return self.version + + def __repr__(self): + return repr(self.version) + + +class Point(NamedTuple): + """区间端点。""" + type_: int # 类型,0为闭区间,1为开区间 + value: Version + + +class Interval(NamedTuple): + """版本号区间。""" + low: Point + high: Point + + @classmethod + def match(cls, input_str: str) -> bool: + """输入字符串是否匹配区间模式。""" + if not input_str.startswith('(') and not input_str.startswith('['): + return False + if not input_str.endswith(')') and not input_str.endswith(']'): + return False + input_str = input_str[1:-1] + if input_str.count(',') > 1: + return False + return True + + @classmethod + def parse(cls, input_str): + """解析版本号区间。""" + if not cls.match(input_str): + raise IntervalFormatNotMatch() + + if input_str[0] == '[': + low_type = 0 + elif input_str[0] == '(': + low_type = 1 + else: + assert False, 'should not go here.' + + if input_str[-1] == ']': + high_type = 0 + elif input_str[-1] == ')': + high_type = 1 + else: + assert False, 'should not go here.' + + input_str = input_str[1:-1] + input_list = input_str.split(',') + low = input_list[0].strip() + if len(input_list) > 1: + high = input_list[1].strip() + else: + high = None + + if low: + low_version = Point(low_type, Version(low)) + else: + low_version = None + + if high: + high_version = Point(high_type, Version(high)) + else: + high_version = None + + return cls(low=low_version, high=high_version) + + def to_required_list(self): + """转换为版本需求字符串列表。""" + result = [] + + if self.low: + if self.low.type_ == 0: + operator = '>=' + else: + operator = '>' + required_str = '{0}{1}'.format(operator, self.low.value.version) + result.append(required_str) + + if self.high: + if self.high.type_ == 0: + operator = '<=' + else: + operator = '<' + required_str = '{0}{1}'.format(operator, self.high.value.version) + result.append(required_str) + + return result + + +class Require(NamedTuple): + """包需求。""" + pkg_name: str + versions: List + + @classmethod + def _sort_key(cls, item) -> Tuple: + """排序键。""" + if isinstance(item, Interval): + # 如果存在区间左值,则左值参与排序。 + if item.low: + return item.low.value, item.low.type_ + # 否则使用区间右值,由于开区间更小,所以type_取负。 + return item.high.value, -item.high.type_ + + return item, 0 + + @classmethod + def _sort_versions(cls, versions: List) -> bool: + """排序版本序列。""" + versions.sort(key=cls._sort_key) + return True + + @classmethod + def _to_required_list(cls, versions: List) -> List[str]: + """转换为版本需求字符串列表。""" + result = [] + for version in versions: + requires = version.to_required_list() + result.extend(requires) + + return result + + @classmethod + def _to_required_str(cls, versions: List) -> str: + """转换为版本需求字符串。""" + requires = cls._to_required_list(versions) + required_str = ', '.join(requires) + + return required_str + + def sort_versions(self) -> bool: + """排序版本序列。""" + return self._sort_versions(self.versions) + + def to_required_full_str(self) -> str: + """转换为版本需求字符串。""" + required_str = self._to_required_str(self.versions) + required_full_str = 'required_package_{0}_version="{1}"'.format(self.pkg_name, required_str) + return required_full_str + + +class ItemElement(NamedTuple): + """item元素。""" + name: str + version: str + + @classmethod + def parse(cls, item_ele: ET.Element, cur_ver: str): + """解析item元素。""" + name = item_ele.attrib['name'] + version = item_ele.attrib['version'].replace("$(CUR_VER)", cur_ver) + return cls(name=name, version=version) + + @classmethod + def skip(cls, item_ele: ET.Element): + """是否跳过item元素。""" + version = item_ele.attrib['version'] + return version.strip() == '' + + +class CompatibleElement(NamedTuple): + """compatible元素。""" + items: List + + @classmethod + def parse(cls, compatible_ele: ET.Element, cur_ver: str): + """解析compatible元素。""" + items = [] + for item_ele in compatible_ele.findall("./item"): + if ItemElement.skip(item_ele): + continue + item = ItemElement.parse(item_ele, cur_ver) + items.append(item) + return cls(items=items) + + +def is_version_number(version: str) -> bool: + """字符串是否为版本号。""" + has_slash = '/' in version + return not has_slash and len(version.split(".")) >= 3 + + +class VersionXml(NamedTuple): + """版本配置。""" + release_version: str + version_dir: str + packages: Dict + + @classmethod + def match(cls, filepath: Union[Path, str]) -> bool: + """文件路径是否匹配版本信息文件。""" + return str(filepath).endswith('.xml') + + @classmethod + def parse_version(cls, version_str: str): + """解析版本配置。""" + ret = Interval.match(version_str) + if ret: + result = Interval.parse(version_str) + return result + + ret = Version.match(version_str) + if ret: + result = Version.parse(version_str) + return result + + raise ParseVersionFailed() + + def get_release_version(self): + """获取发布版本号。""" + return self.release_version + + def get_version_dir(self): + """获取多版本目录。""" + return self.version_dir + + def collect_requires(self, package: str) -> List[Require]: + """收集对应包的包需求列表。""" + requires = {} + + if package not in self.packages: + return [] + + compatible = self.packages[package] + + for item in compatible.items: + pkg_name = item.name + if pkg_name not in requires: + requires[pkg_name] = Require(pkg_name=pkg_name, versions=[]) + + version_str = item.version + try: + version = self.parse_version(version_str) + except ParseVersionFailed as ex: + msg = f'parse pkg {pkg_name} version {version_str} failed' + raise CollectRequiresFailed(pkg_name, version_str, msg) from ex + + requires[pkg_name].versions.append(version) + + result = [] + for pkg_name in sorted(requires.keys()): + requires[pkg_name].sort_versions() + result.append(requires[pkg_name]) + + return result + + +def get_version_dir(version_xml: Optional[VersionXml], + disable_multi_version: bool, + version_dir: Optional[str]) -> Optional[str]: + """获取版本目录名。""" + if disable_multi_version: + return None + + if version_dir: + return version_dir + + # 支持从version.xml中获取version_dir + if version_xml and version_xml.get_version_dir(): + return version_xml.get_version_dir() + + return None + + +def is_multi_version(version_dir: str) -> bool: + """是否多版本。""" + return bool(version_dir) + + +class VersionInfo(NamedTuple): + """版本信息。""" + install_version_info: bool + install_version_info_attrib: Optional[Dict[str, str]] + itf_versions: List[str] + version: str + version_xml: Optional[VersionXml] + timestamp: Optional[str] + + +class VersionInfoFile(NamedTuple): + """生成的版本配置。""" + version: str + itf_version_info: Optional[str] = None + requires: Optional[List[Require]] = None + version_dir: Optional[str] = None + timestamp: Optional[str] = None + + def _get_content(self) -> str: + """获取版本配置内容。""" + lines = ['Version={0}'.format(self.version)] + if self.version_dir: + lines.append('version_dir={0}'.format(self.version_dir)) + if self.timestamp: + lines.append('timestamp={0}'.format(self.timestamp)) + if self.itf_version_info: + lines.append(self.itf_version_info) + + if self.requires: + requires_str = [require.to_required_full_str() for require in self.requires] + lines.extend(requires_str) + + lines.append('') + + return '\n'.join(lines) + + def save(self, target_path: Union[Path, str]): + """保存版本配置。""" + content = self._get_content() + + target_dir = os.path.dirname(target_path) + if not os.path.exists(target_dir): + os.makedirs(target_dir) + + with open(target_path, 'w') as file: + file.write(content) diff --git a/scripts/package/common/sh/check_version_required.awk b/scripts/package/common/sh/check_version_required.awk new file mode 100644 index 0000000000000000000000000000000000000000..10d2db9d6fba0b7465136b2609a19ac49e22ff10 --- /dev/null +++ b/scripts/package/common/sh/check_version_required.awk @@ -0,0 +1,281 @@ +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +function strip(input) { + sub("^ +", "", input) + sub(" +$", "", input) + return input +} + +function check_compatible_le(version_arr, len_version_arr, require_arr, len_require_arr, i) { + for (i = 1; i <= len_require_arr; i++) { + if (require_arr[i] == "") { + continue + } + # len_version_arr lt len_require_arr + if (i > len_version_arr) { + return 1 + } + if (version_arr[i] < require_arr[i]) { + return 1 + } + if (version_arr[i] > require_arr[i]) { + return 0 + } + } + if (len_version_arr > len_require_arr) { + return 1 + } + # len_version_arr eq len_require_arr + return 1 +} + +function check_compatible_lt(version_arr, len_version_arr, require_arr, len_require_arr, i) { + for (i = 1; i <= len_require_arr; i++) { + if (require_arr[i] == "") { + continue + } + # len_version_arr lt len_require_arr + if (i > len_version_arr) { + return 1 + } + if (version_arr[i] < require_arr[i]) { + return 1 + } + if (version_arr[i] > require_arr[i]) { + return 0 + } + } + if (len_version_arr > len_require_arr) { + return 0 + } + # len_version_arr eq len_require_arr + return 0 +} + +function check_compatible_ge(version_arr, len_version_arr, require_arr, len_require_arr, i) { + for (i = 1; i <= len_require_arr; i++) { + if (require_arr[i] == "") { + continue + } + # len_version_arr lt len_require_arr + if (i > len_version_arr) { + return 0 + } + if (version_arr[i] < require_arr[i]) { + return 0 + } + if (version_arr[i] > require_arr[i]) { + return 1 + } + } + if (len_version_arr > len_require_arr) { + return 1 + } + # len_version_arr eq len_require_arr + return 1 +} + +function check_compatible_gt(version_arr, len_version_arr, require_arr, len_require_arr, i) { + for (i = 1; i <= len_require_arr; i++) { + if (require_arr[i] == "") { + continue + } + # len_version_arr lt len_require_arr + if (i > len_version_arr) { + return 0 + } + if (version_arr[i] < require_arr[i]) { + return 0 + } + if (version_arr[i] > require_arr[i]) { + return 1 + } + } + if (len_version_arr > len_require_arr) { + return 1 + } + # len_version_arr eq len_require_arr + return 0 +} + +function check_compatible_eq(version_arr, len_version_arr, require_arr, len_require_arr, i) { + for (i = 1; i <= len_require_arr; i++) { + if (require_arr[i] == "") { + continue + } + # len_version_arr lt len_require_arr + if (i > len_version_arr) { + return 0 + } + if (version_arr[i] != require_arr[i]) { + return 0 + } + } + if (len_version_arr > len_require_arr) { + return 1 + } + # len_version_arr eq len_require_arr + return 1 +} + +function check_compatible(version_arr, len_version_arr, require, require_arr, len_require_arr, pos) { + len_require_arr = split(require, require_arr, ".") + + pos = match(require_arr[1], /^>=/) + if (pos != 0) { + require_arr[1] = substr(require_arr[1], pos + RLENGTH) + return check_compatible_ge(version_arr, len_version_arr, require_arr, len_require_arr) + } + + pos = match(require_arr[1], /^>/) + if (pos != 0) { + require_arr[1] = substr(require_arr[1], pos + RLENGTH) + return check_compatible_gt(version_arr, len_version_arr, require_arr, len_require_arr) + } + + pos = match(require_arr[1], /^<=/) + if (pos != 0) { + require_arr[1] = substr(require_arr[1], pos + RLENGTH) + return check_compatible_le(version_arr, len_version_arr, require_arr, len_require_arr) + } + + pos = match(require_arr[1], /^/) + if (pos != 0) { + gt_require = 1 + lt_require = 0 + eq_require = 0 + } else { + pos = match(all_required_arr[i], /^> "${LOG_FILE}" +} + +# 设置日志参数 +set_comm_log() { + local pkg_name="$1" + local log_file="$2" + + LOG_PKG_NAME="${pkg_name}" + if [ "$log_file" != "" ]; then + LOG_FILE="${log_file}" + fi +} + +# 安全日志 +comm_log_operation() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + local operation="$1" + local runfilename="$2" + local result="$3" + local installmode="$4" + local all_parma="$5" + local level="" + if [ "${operation}" = "Install" ]; then + level="SUGGESTION" + elif [ "${operation}" = "Upgrade" ]; then + level="MINOR" + elif [ "${operation}" = "Uninstall" ]; then + level="MAJOR" + else + level="UNKNOWN" + fi + + if [ ! -f "${COMM_OPERATION_LOGFILE}" ]; then + touch "${COMM_OPERATION_LOGFILE}" + chmod 640 "${COMM_OPERATION_LOGFILE}" + fi + + echo "${operation} ${level} ${COMM_USERNAME} ${cur_date} 127.0.0.1 ${runfilename} ${result} installmode=${installmode}; cmdlist=${all_parma}" >> "${COMM_OPERATION_LOGFILE}" +} + +## end module + +# 转换--install-for-all参数下文件权限 +comm_set_install_for_all_mod() { + local _outvar="$1" + local _mod="$2" + local _new_mod + + # ${parameter%word} Remove matching suffix pattern. + local _new_mod="${_mod%?}" + # ${parameter#word} Remove matching prefix pattern. + local _new_mod="${_new_mod}${_new_mod#${_new_mod%?}}" + + eval "${_outvar}=\"${_new_mod}\"" +} + +# 创建文件 +comm_create_file() { + local path="$1" + local mod="$2" + local own="$3" + local install_for_all="$4" + + if [ -d "$path" ]; then + comm_log "WARNING" "remove existed dir $path before create file." + rm -rf "$path" + fi + touch "$path" + if [ $? -ne 0 ]; then + comm_log "WARNING" "create file $path failed." + return 1 + fi + + if [ "$install_for_all" = "true" ] || [ "$install_for_all" = "y" ]; then + comm_set_install_for_all_mod "mod" "$mod" + fi + chmod "$mod" "$path" + if [ $? -ne 0 ]; then + comm_log "WARNING" "chmod path $path $mod failed." + return 1 + fi + + chown "$own" "$path" + if [ $? -ne 0 ]; then + comm_log "WARNING" "chown path $path $own failed." + return 1 + fi + return 0 +} + +# 创建目录 +comm_create_dir() { + local path="$1" + local mod="$2" + local own="$3" + local install_for_all="$4" + + if [ "$path" = "" ]; then + comm_log "WARNING" "dir path is empty" + return 1 + fi + + if [ ! -d "$path" ]; then + mkdir -p "$path" + if [ $? -ne 0 ]; then + comm_log "WARNING" "create dir $path failed." + return 1 + fi + fi + + if [ "$install_for_all" = "true" ] || [ "$install_for_all" = "y" ]; then + comm_set_install_for_all_mod "mod" "$mod" + fi + chmod "$mod" "$path" + if [ $? -ne 0 ]; then + comm_log "WARNING" "chmod path $path $mod failed." + return 1 + fi + + chown -f "$own" "$path" + if [ $? -ne 0 ]; then + comm_log "WARNING" "chown path $path $own failed." + return 1 + fi +} + +# 创建子包目录 +comm_create_package_dir() { + local package_dir="$1" + local own="$2" + local install_for_all="$3" + if [ ! -d "$package_dir" ]; then + comm_create_dir "$package_dir" "755" "$own" "$install_for_all" + fi +} + +# 创建install_info文件 +comm_create_install_info_by_path() { + local install_info="$1" + local own="$2" + if [ ! -f "$install_info" ]; then + comm_create_file "$install_info" "640" "$own" "false" + fi +} + +# 更新安装参数 +comm_update_install_param() { + local key="$1" + local val="$2" + local file="$3" + local param="" + if [ ! -f "${file}" ]; then + return 1 + fi + param="$(grep -i "^${key}=" "${file}")" + if [ "${param}" = "" ]; then + echo "${key}=${val}" >> "${file}" + else + sed -i "/^${key}=/Ic ${key}=${val}" "${file}" + fi +} + +# 获取安装参数 +# _outvar : [输出变量],安装参数值 +# _file : install.info文件路径 +# _key : 参数名 +comm_get_install_param() { + local _outvar="$1" + local _file="$2" + local _key="$3" + local _result + + if [ ! -f "${_file}" ]; then + comm_log "WARNING" "file ${_file} doesn't exist in get install param." + return 1 + fi + _result="$(grep -i "^${_key}=" "${_file}" | cut -d"=" -f2-)" + eval "${_outvar}=\"${_result}\"" +} + +# 更新安装参数文件 +comm_update_install_info() { + local install_path_param="" + local install_type="" + local username="" + local usergroup="" + local feature_type="" + local package install_info + + while true + do + case "$1" in + --install-path-param=*) + install_path_param="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --install-type=*) + install_type="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --username=*) + username="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --usergroup=*) + usergroup="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --feature-type=*) + feature_type="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + *) + break + ;; + esac + done + + if [ $# -lt 2 ]; then + return 1 + fi + + package="$1" + install_info="$2" + + if [ "$install_path_param" != "" ]; then + comm_update_install_param "${package}_Install_Path_Param" "$install_path_param" "$install_info" + fi + if [ "$install_type" != "" ]; then + comm_update_install_param "${package}_Install_Type" "$install_type" "$install_info" + fi + if [ "$username" != "" ]; then + comm_update_install_param "${package}_UserName" "$username" "$install_info" + fi + if [ "$usergroup" != "" ]; then + comm_update_install_param "${package}_UserGroup" "$usergroup" "$install_info" + fi + if [ "$feature_type" != "" ]; then + comm_update_install_param "${package}_Feature_Type" "$feature_type" "$install_info" + fi +} + +# 开始安装前打印开始信息 +comm_start_log() { + local all_parma="$@" + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + comm_log "INFO" "Start time:$cur_date" + comm_log "INFO" "LogFile:${COMM_LOGFILE}" + comm_log "INFO" "InputParams:$all_parma" + comm_log "INFO" "OperationLogFile:${COMM_OPERATION_LOGFILE}" +} + +# 安装结束退出前打印结束信息 +comm_exit_log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + comm_log "INFO" "End time:${cur_date}" + exit "$1" +} + +comm_print_usage() { + local runfilename="$1" + comm_log "INFO" "Please input this command for help: ./${runfilename} --help" +} + +# 判断安装路径是否合法 +comm_judgmentpath() { + local install_path="$1" + local pkg_name="$2" + check_install_path_valid "$install_path" + if [ $? -ne 0 ]; then + comm_log "ERROR" "The $pkg_name install_path $install_path is invalid, only characters in [a-z,A-Z,0-9,-,_] are supported!" + exit 1 + fi +} + +# 标准化安装路径 +# _outvar : [输出变量],处理后的安装路径 +# _install_path : 安装路径 +comm_normalize_install_path() { + local _outvar="$1" + local _install_path="$2" + local _slashes_num _result + _slashes_num=$(echo "$_install_path" | grep -o '/' | wc -l) + if [ "$_slashes_num" -gt 1 ]; then + _result=$(echo "$_install_path" | sed "s/\/*$//g") + else + _result="$_install_path" + fi + eval "${_outvar}=\"${_result}\"" +} + +# 解析安装路径 +# _outvar : [输出变量],处理后的安装路径 +# _install_path : 安装路径 +# _pkg_name : 包名 +comm_parse_install_path() { + local _outvar="$1" + local _install_path="$2" + local _pkg_name="$3" + + comm_judgmentpath "$_install_path" "$_pkg_name" + comm_normalize_install_path "$_outvar" "$_install_path" +} + +############### 错误函数 ############### +# 文件没有找到 +comm_err_file_or_directory_not_exist() { + comm_log "ERROR" "The file or directory doesn't exist, $1" + comm_exit_log 1 +} + +os_name() { + if [ ! -f "$1" ];then + HostOsName=unknown + HostOsFullName=unknown + HostOsVersion=unknown + return + fi + + HostOsName=$(cat "$1" | grep ^NAME= | awk -F "[\" ]" '{print $2}') + HostOsFullName=$(cat "$1" | grep ^NAME= | awk -F "\"" '{print $2}') + + if [ x"$HostOsName" = "x" ];then + HostOsName=$(cat "$1" | grep ^NAME= | awk -F "[=]" '{print $2}') + HostOsFullName=$(cat "$1" | grep ^NAME= | awk -F "\"" '{print $2}') + fi + if [ x"$HostOsName" = "x" ];then + HostOsName=unknown + HostOsFullName=unknown + fi + HostOsVersion=$(cat "$1" | grep ^VERSION_ID= | awk -F "\"" '{print $2}') + if [ x"$HostOsVersion" = "x" ];then + HostOsVersion=unknown + fi + return +} + +get_os_info() { + if [ -f /etc/os-release ];then + os_name /etc/os-release + elif [ -f /etc/centos-release ];then + HostOsName=CentOS + HostOsFullName="CentOS Linux" + HostOsVersion=$(cat /etc/centos-release | awk '{print $4}') + else + which lsb_release >/dev/null 2>&1 + if [ $? -eq 0 ];then + HostOsName=$(lsb_release -si) + HostOsFullName="${HostOsName}" + HostOsVersion=$(lsb_release -sr) + else + os_name /etc/issue + fi + fi + return +} + +get_system_info() { + get_os_info + HostArch=$(uname -m) + KernelVersion=$(uname -r) +} + +version_gt() { + if [ "$2"x = "x" ];then + return 0 + else + test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1" + fi +} +version_le() { + if [ "$2"x = "x" ];then + return 0 + else + test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" + fi +} +version_lt() { + if [ "$2"x = "x" ];then + return 0 + else + test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1" + fi +} +version_ge() { + if [ "$2"x = "x" ];then + return 0 + else + test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" = "$1" + fi +} + +version_vaild() { + local ver_range="$1" #version range + local ver="$2" #version provider + local clean_ver_range=$(echo "$ver_range" | sed 's/"//g') # clean ver_range,去除引号啥的 + local new_ver_range=$(echo "$clean_ver_range" | sed 's/\[//' | sed 's/\]//' | sed 's/(//' | sed 's/)//') #处理过的version range,去除[],() 得到类似 1.0,2.0 + + local start=$(echo $new_ver_range | awk -F ',' '{print $1}') + local end=$(echo $new_ver_range | awk -F ',' '{print $2}') + + if echo $clean_ver_range | grep -Eq "^\[.*\]$" ; then + # 闭合区间 [a,b]={x|a<=x<=b} + if version_ge $ver $start && version_le $ver $end ; then + # pass + return 0 + fi + elif echo $clean_ver_range | grep -Eq "^\[.*\)$"; then + # 左闭右开 [a,b)={x|a<=x= require_ver 结果pass 否则 nopass。即依赖包的当前版本大于等于需求 + if version_ge $ver $clean_ver_range ;then + return 0 + fi + fi + #not pass + return 1 +} + +# 检查包接口版本。 +# 输出VerCheckStatus和ver_check_status变量。 +check_pkg_ver_deps() { + ver_path="$1" + req_pkg="$2" + req_ver_path="$3" + + ver_info_list=$(awk -F '[_=]' '$1=="required" && $2=="'$req_pkg'" {print $1":"$2":"$3":"$4":"$5}' "$ver_path") + + for line in ${ver_info_list} + do + itf=`echo $line | cut -d":" -f 3` + ver=`echo $line | cut -d":" -f 5` + req_ver=`awk -F '=' '$1=="'$itf'_version" {print $2}' "$req_ver_path"` + if ! version_vaild $ver $req_ver; then + VerCheckStatus=FAIL + ver_check_status=FAIL + return + fi + done + VerCheckStatus=SUCC + ver_check_status=SUCC +} + +# 检查安装路径是否合法。 +# install_path : 安装路径 +check_install_path_valid() { + local install_path="$1" + # 黑名单设置,不允许//,...这样的路径 + if echo "${install_path}" | grep -Eq '\/{2,}|\.{3,}'; then + return 1 + fi + # 白名单设置,只允许常见字符 + if echo "${install_path}" | grep -Eq '^\~?[a-zA-Z0-9./_-]*$'; then + return 0 + else + return 1 + fi +} + +# 创建相对软链接 +# mdc的release包场景,ln命令不支持-r参数,需要手动实现相对软链功能 +# 入参需要是规范(绝对)路径,完整路径。例如:目标路径不能是一个目录,否则相对软链计算结果不正确 +# src_path : 源路径 +# dst_path : 目标路径 +create_softlink_icp_relative() { + local src_path="$1" + local dst_path="$2" + local source="top${src_path}" + local target="top${dst_path}" + + # 若变量内容从尾向前的数据符合,则将符合的最短数据删除 + local common="${target%/*}" + # 若变量内容从头开始的数据符合,则将符合的最短数据删除 + local forward="${source#"$common"/}" + + local result="" + + while [ "${forward}" = "${source}" ]; do + common="$(dirname "$common")" + forward="${source#"$common"/}" + result="../${result}" + done + + result="${result}${forward}" + + ln -sfn "${result}" "${dst_path}" + if [ $? -ne 0 ]; then + log "ERROR" "create softlink relative from ${src_path} to ${dst_path} failed!" + return 1 + fi + return 0 +} + +# 创建软链接 +create_softlink() { + local _src_dir="$1" + local _dst_dir="$2" + local _sub_dir_src="$3" + local _sub_dir_dst="$4" + local _sub_dir_dst_new _dst_path ret total_ret=0 + + # 注意_sub_dir_src可能有通配符 + for _src_path in "${_src_dir}"/${_sub_dir_src} + do + if [ -z "$_sub_dir_dst" ]; then + _sub_dir_dst_new="$(basename "${_src_path}")" + else + _sub_dir_dst_new="${_sub_dir_dst}" + fi + _dst_path="${_dst_dir}/${_sub_dir_dst_new}" + if [ -L "${_dst_path}" ]; then + rm -f "${_dst_path}" + fi + # 目标取规范化路径 + _dst_path="$(readlink -f "${_dst_path}")" + if [ -d "${_dst_path}" ]; then + # 如果目标为目录,拼接上源文件名 + _dst_path="${_dst_path}/$(basename "${_src_path}")" + fi + + # 源取规范化路径 + _src_path="$(readlink -f "${_src_path}")" + + create_softlink_icp_relative "${_src_path}" "${_dst_path}" + ret="$?" && [ $ret -ne 0 ] && total_ret=$ret + done + + return $total_ret +} + +# 创建软链接,调用ln -r命令 +create_softlink_by_relative_ln() { + local _src_dir="$1" + local _dst_dir="$2" + local _sub_dir_src="$3" + local _sub_dir_dst="$4" + local _src_path="$_src_dir/$_sub_dir_src" + # 注意_src_path可能有通配符,处理流程中需要考虑通配场景。 + local _dst_path + if [ -z "$_sub_dir_dst" ]; then + _sub_dir_dst=$(basename $_src_path) + fi + _dst_path="$_dst_dir/$_sub_dir_dst" + if [ -L "${_dst_path}" ]; then + rm -f "${_dst_path}" + fi + ln -sr $_src_path $_dst_path +} + +# 如果源文件存在,则创建软链接 +create_softlink_if_exists() { + local _src_dir="$1" + local _sub_dir_src="$3" + local _src_path="$_src_dir/$_sub_dir_src" + + if [ -e $_src_path ]; then + create_softlink "$@" + fi +} + +# 目录是否为空 +# 空目录返回0 +# 目录不存在返回1 +# 目录非空或无权限访问返回2 +is_dir_empty() { + # 如果目录不存在,则返回 + if [ ! -d "$1" ]; then + return 1 + fi + # 否则检查目录是否为空 + # 2>&1重定向无权限访问报错信息 + if [ "$(ls -A "$1" 2>&1)" != "" ]; then + return 2 + fi + return 0 +} + +# 删除空目录 +remove_dir_if_empty() { + local dirpath="$1" + + if is_dir_empty "${dirpath}"; then + rm -rf "${dirpath}" + fi + return 0 +} + +# 删除目录 +remove_dir() { + local dirpath="$1" + + if [ -e "${dirpath}" ]; then + chmod u+w -R "${dirpath}" + fi + rm -rf "${dirpath}" + + return 0 +} + +# 删除软链接 +remove_softlink() { + local path="$1" + [ -L "${path}" ] && rm -f "${path}" +} + +# 处理pre_check +# pkg_name : 包名 +# pre_check_func : pre_check函数 +# standalone : 是否为独立的pre_check命令[y/n] +process_pre_check() { + local pkg_name="$1" + local pre_check_func="$2" + local standalone="$3" + + log "INFO" "${pkg_name} do pre_check started." + ${pre_check_func} + ret=$? + if [ $ret -ne 0 ]; then + log "WARNING" "${pkg_name} do pre check failed." + fi + log "INFO" "${pkg_name} do pre_check finished." + + if [ "${standalone}" = "y" ]; then + if [ $ret -ne 0 ]; then + exitInstallLog 1 + fi + exitInstallLog 0 + fi +} + +# 包是否在环境上安装 +# install_path : 安装路径 +# pkgname : 包名 +# varname : [输出变量],包是否在环境上安装 +does_pkg_installed() { + local install_path="$1" + local pkgname="$2" + local varname="$3" + local result="true" + local pkg_path="${install_path}/${pkgname}" + local script_path="${pkg_path}/script" + + if [ -L "${pkg_path}" ]; then + result="false" + fi + + if [ ! -d "${pkg_path}" ]; then + result="false" + fi + + if [ -L "${script_path}" ]; then + result="false" + fi + + if [ ! -d "${script_path}" ]; then + result="false" + fi + + eval "${varname}=\"${result}\"" +} + + +# 获取驱动包安装路径 +# 搜索顺序: +# 1. 查看同级目录下是否存在driver包 +# 2. 查看/etc/ascend_install.info中配置的路径 +# _outvar : [输出变量],driver包安装路径 +# _install_path : 安装路径 +get_driver_install_path() { + local _outvar="$1" + local _install_path="$2" + + local _install_info="/etc/ascend_install.info" + local _ascend_hal_name="libascend_hal.so" + local _old_ifs + local _var + local _driver_install_path + local _ldconfig_result + local _ldconfig_cnt + + if [ -d "${_install_path}/driver" ]; then + eval "${_outvar}=\"${_install_path}\"" + return 0 + fi + + # 第一种方案 + if [ -f ${_install_info} ]; then + . ${_install_info} + if [ ! -z ${Driver_Install_Path_Param} ]; then + _driver_install_path="${Driver_Install_Path_Param}" + eval "${_outvar}=\"${_driver_install_path}\"" + return 0 + fi + fi + + eval "${_outvar}=\"\"" +} + +# 执行卸载脚本 +# install_path : 安装路径 +# pkgname : 包名 +run_uninstall_script() { + local install_path="$1" + local pkgname="$2" + local uninstall_path="${install_path}/${pkgname}/script/uninstall.sh" + + if [ -f "${uninstall_path}" ]; then + "${uninstall_path}" + return $? + else + return 1 + fi +} + +# 获取包版本。 +get_package_version() { + local _outvar="$1" + local _version_info_path="$2" + local _result + + if [ ! -f "${_version_info_path}" ]; then + eval "${_outvar}=\"\"" + return 1 + fi + + _result="$(grep "^Version=" "${_version_info_path}" | cut -d= -f2-)" + eval "${_outvar}=\"${_result}\"" +} + +# 获取包版本 +# _outvar : [输出变量],包版本 +# _version_info_path : version.info文件路径 +get_version() { + get_package_version "$@" +} + +# 获取包版本目录 +# _outvar : [输出变量],包版本目录 +# _version_info_path : version.info文件路径 +get_version_dir() { + local _outvar="$1" + local _version_info_path="$2" + local _result + + if [ ! -f "${_version_info_path}" ]; then + eval "${_outvar}=\"\"" + return 1 + fi + + _result="$(grep "^version_dir=" "${_version_info_path}" | cut -d= -f2-)" + eval "${_outvar}=\"${_result}\"" +} + +# 获取包架构 +# _outvar : [输出变量],包架构 +# _scene_info_path : scene.info文件路径 +get_arch() { + local _outvar="$1" + local _scene_info_path="$2" + local _result + + if [ ! -f "${_scene_info_path}" ]; then + eval "${_outvar}=\"\"" + return 1 + fi + + _result="$(grep "^arch=" "${_scene_info_path}" | cut -d= -f2-)" + eval "${_outvar}=\"${_result}\"" +} + +# 获取包目录 +# _outvar : [输出变量],包目录 +# _version_info_path : version.info文件路径 +# _install_path : 安装路径 +# _pkg_name : 包名 +get_install_package_dir() { + local _outvar="$1" + local _version_info_path="$2" + local _install_path="$3" + local _pkg_name="$4" + local _pkg_is_multi_version _pkg_version_dir _result + + is_multi_version_pkg "_pkg_is_multi_version" "$_version_info_path" + get_version_dir "_pkg_version_dir" "$_version_info_path" + + if [ "$_pkg_is_multi_version" = "true" ]; then + _result="$_install_path/$_pkg_version_dir/$_pkg_name" + else + _result="$_install_path/$_pkg_name" + fi + eval "${_outvar}=\"${_result}\"" +} + +# 包名转换为日志输出的包名(首字母大写) +_package_to_log_pkg_name() { + local _outvar="$1" + local _pkg_name="$2" + + local _result + + _result="$(awk -v pkg_name="${_pkg_name}" ' + BEGIN {print toupper(substr(pkg_name, 1, 1)) substr(pkg_name, 2)} + ')" + + eval "${_outvar}=\"${_result}\"" +} + +# 获取首字母大字的包名 +get_titled_package_name() { + _package_to_log_pkg_name "$@" +} + +# 安装前处理。 +# 返回码: +# 0: 成功 +# 1: 版本兼容性检查失败 +# 调用方式: +# preinstall_process --install-path= --script-dir= --package= --logfile= [ --logstyle= ] [ --docker-root= ] +# +# --install-path= : 安装路径 +# --script-dir= : 当前脚本目录路径 +# --package= : 当前包名 +# --logfile= : ascend_install.log日志文件路径 +# --logstyle= : 日志风格 +# --docker-root= : docker根路径 +preinstall_process() { + local install_path="" + local docker_root="" + local script_dir="" + local package="" + local logfile="" + local real_install_path + local version_info_path + local ret + + # 参数列表末尾添加--参数 + eval set -- "$@ --" + + while true + do + case "$1" in + --install-path=*) + install_path="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --docker-root=*) + docker_root="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --script-dir=*) + script_dir="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --package=*) + package="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --logfile=*) + logfile="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --logstyle=*) + LOG_STYLE="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + *) + break + ;; + esac + done + + if [ "${install_path}" = "" ]; then + echo "error: install_path is needed!" + return 1 + fi + if [ "${script_dir}" = "" ]; then + echo "error: script_dir is needed!" + return 1 + fi + + if [ "${package}" = "" ]; then + echo "error: package is needed!" + return 1 + fi + if [ "${logfile}" = "" ]; then + echo "error: logfile is needed!" + return 1 + fi + + LOG_FILE="${logfile}" + _package_to_log_pkg_name "LOG_PKG_NAME" "${package}" + + if [ "${docker_root}" = "" ]; then + real_install_path="${install_path}" + else + real_install_path="${docker_root}/${install_path}" + fi + + version_info_path="$(pwd)/version.info" + + _check_version_compatiable "${version_info_path}" "${real_install_path}" "${script_dir}" + ret=$? + if [ $ret -ne 0 ]; then + return 1 + fi + + return 0 +} + +# 安装前检查。 +# 返回码: +# 0: 成功 +# 1: 版本兼容性检查失败 +# 调用方式: +# preinstall_check --install-path= --script-dir= --package= --logfile= [ --logstyle= ] [ --docker-root= ] +# +# --install-path= : 安装路径 +# --script-dir= : 当前脚本目录路径 +# --package= : 当前包名 +# --logfile= : ascend_install.log日志文件路径 +# --logstyle= : 日志风格 +# --docker-root= : docker根路径 +preinstall_check() { + preinstall_process "$@" +} + +# 是否为多版本包 +# 读取version.info文件,检查本包是否为多版本包 +# _outvar : [输出变量],是否为多版本包 +# _filepath : version.info文件路径 +is_multi_version_pkg() { + local _outvar="$1" + local _filepath="$2" + local _ret="false" + + if [ -f "${_filepath}" ]; then + grep "^version_dir=" "${_filepath}" > /dev/null + [ $? -eq 0 ] && _ret="true" + fi + eval "${_outvar}=\"${_ret}\"" +} + +# 文件列表的某一列 +_filelist_column() { + local _filepath="$1" + local _idx="$2" + tail -n +2 "$_filepath" | cut -d, -f${_idx} | sort | uniq +} + +# 移除comm特性 +_remove_comm_feature() { + local _outvar="$1" + local _feature="$2" + local _result + + _result="$(echo "$_feature" | sed 's/comm//g' | sed 's/,,/,/g' | sed 's/^,//g' | sed 's/,$//g')" + eval "${_outvar}=\"${_result}\"" +} + +# 特性列表转换为正则表达式 +_feature_to_regex() { + local _outvar="$1" + local _feature="$2" + local _result_ftr + _result_ftr="\b(($(echo "$_feature" | sed 's/,/)|(/g')))\b" + eval "${_outvar}=\"${_result_ftr}\"" +} + +# 是否包含指定feature +# 读取filelist.csv文件,检查是否包含指定feature +# _outvar : [输出变量](true/false),是否包含指定feature +# _feature : 指定feature,可指定多个,以“,”分隔,如:dvpp,audio +# _filepath : filelist.csv文件路径 +contain_feature() { + local _outvar="$1" + local _feature="$2" + local _filepath="$3" + local _feature_regex _feature_cf + + # 输入的comm不作为特性,也就是说不支持--feature=comm + _remove_comm_feature "_feature_cf" "$_feature" + if [ "$_feature_cf" = "" ]; then + eval "${_outvar}=\"false\"" + return 0 + fi + + _feature_to_regex "_feature_regex" "$_feature_cf" + _filelist_column "$_filepath" 10 | grep -E "$_feature_regex" > /dev/null 2>&1 + if [ $? -eq 0 ]; then + eval "${_outvar}=\"true\"" + else + eval "${_outvar}=\"false\"" + fi +} + +# 向filelist.csv中写入1个条目 +# filepath : filelist.csv文件路径 +# operation : 操作类型 +# path_in_pkg : 包内路径 +# install_path : 安装路径 +# permission : 文件权限 +# owner_group : 文件属主,支持默认值DEFAULT +# install_type : 安装类型 +# softlink : 软链接 +# block : 所属块 +# feature : 所属特性,支持默认值DEFAULT +# chip : 所属芯片,支持默认值DEFAULT +# arch : 包架构 +add_fileitem() { + local filepath="$1" + local operation="$2" + local path_in_pkg="$3" + local install_path="$4" + local permission="$5" + local owner_group="$6" + local install_type="$7" + local softlink="$8" + local pkg_inner_softlink="$9" + local block="${10}" + local feature="${11}" + local chip="${12}" + local arch="${13}" + local is_common_path="N" + + if [ "$owner_group" = "DEFAULT" ]; then + owner_group="\\\\\$username:\\\\\$usergroup" + fi + + if [ "$feature" = "DEFAULT" ]; then + feature="all" + fi + + if [ "$chip" = "DEFAULT" ]; then + chip="all" + fi + + if echo "$install_path" | grep "^${arch}-linux/" > /dev/null; then + is_common_path="Y" + fi + + echo "NA,${operation},${path_in_pkg},${install_path},FALSE,${permission},${owner_group},${install_type},${softlink},${feature},${is_common_path},FALSE,NA,${block},${pkg_inner_softlink},${chip}" >> ${filepath} +} + +# 设置公共变量 +set_global_vars() { + local arch + local scene_filepath="${curpath}/../scene.info" + + if [ -f "${scene_filepath}" ]; then + get_scene_arch "arch" "${scene_filepath}" + if [ "${arch}" != "" ]; then + PKG_ARCH="${arch}" + fi + fi +} + +# 获取并发进程数 +get_thread_num() { + local _outvar="$1" + local _thread_num="$(cat /proc/cpuinfo | grep "^processor" | wc -l)" + + # 未取得CPU核数时,默认为1 + if [ "$_thread_num" = "" ] || [ "$_thread_num" = "0" ]; then + _thread_num="1" + fi + + # CPU核数2倍 + eval "${_outvar}=\"$((_thread_num*2))\"" +} + +# 初始化fifo,用于并发控制 +init_fifo() { + local _outvar="$1" + local _thread_num="$2" + local _tmppath_if tmp + local _skip_msg="skip init fifo" + + # 并发数为空时,默认为1 + if [ "$_thread_num" = "" ]; then + _thread_num="1" + comm_log "WARNING" "thread number is empty, use ${_thread_num}." + fi + # 并发数<=0时,默认为1 + if [ $_thread_num -le 0 ]; then + comm_log "WARNING" "thread number is ${_thread_num}, use 1." + _thread_num="1" + fi + + get_tmp_file _tmppath_if "fifo" + if [ -e "$_tmppath_if" ]; then + rm -rf "$_tmppath_if" + check_ret_warning "$?" "remove old file $_tmppath_if failed, ${_skip_msg}." + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + mkfifo "$_tmppath_if" + check_ret_warning "$?" "make fifo $_tmppath_if failed, ${_skip_msg}." + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 使用文件描述符8作并发控制 + exec 8<> "$_tmppath_if" # 创建文件描述符8 + check_ret_warning "$?" "open fifo $_tmppath_if file descriptor failed, ${_skip_msg}." + ret="$?" && [ $ret -ne 0 ] && return $ret + + rm -f "$_tmppath_if" + check_ret_warning "$?" "remove fifo $_tmppath_if failed, ${_skip_msg}." + ret="$?" && [ $ret -ne 0 ] && return $ret + + for tmp in $(seq $_thread_num); do + echo >&8 + check_ret_warning "$?" "echo fifo $_tmppath_if failed, ${_skip_msg}." + ret="$?" && [ $ret -ne 0 ] && return $ret + done + + eval "${_outvar}=\"${_tmppath_if}\"" +} + +# 根据参数执行 +exec_with_param() { + local param="$1" + shift 1 + local exec_mode fifo_path="$PARALLEL_FIFO" tmp + extract_1st "exec_mode" "$param" + if [ "$exec_mode" = "concurrency" ]; then + if [ "$fifo_path" = "none" ] || [ "$fifo_path" = "" ]; then + "$@" & + else + read tmp <&8 + { + "$@" + ret="$?" + echo >&8 + exit $ret + } & + fi + else + "$@" + fi +} diff --git a/scripts/package/common/sh/common_func_v2.inc b/scripts/package/common/sh/common_func_v2.inc new file mode 100644 index 0000000000000000000000000000000000000000..0cc4b8e10f5482ff45bdaa10cc9590705452739f --- /dev/null +++ b/scripts/package/common/sh/common_func_v2.inc @@ -0,0 +1,1709 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +# 公共函数库 +# 总setenv文件权限 +SETENV_MOD="550" +# 总setenv文件可写状态权限 +SETENV_WRITEABLE_MOD="600" +# 默认特性配置 +DEFAULT_FEATURE_PARAM="all n all" +#export PS4='+ ${FUNCNAME[0]:+${FUNCNAME[0]}():} ${BASH_SOURCE}:${LINENO}: ' +#set -x +RESET_MOD="750" + +# db.info文件格式如下 +# --- +# CommonLib|atc,fwkacllib +# Compiler|atc,fwkacllib +# --- +# 使用"|"分隔模块名和包名列表,包名列表使用","分隔 +# 文件中块名保持以升序排序 +PKG_DB_INFO_RELPATH="var/ascend_package_db.info" +# 缓存mod文件名 +STASH_MOD_PATH="stash_mod.txt" +# stash_mod文件权限 +STASH_FILE_MOD="600" + +# 写日志 +log() { + local cur_date_="$(date +"%Y-%m-%d %H:%M:%S")" + local log_type_="${1}" + local msg_="${2}" + local log_format_="[Common] [${cur_date_}] [${log_type_}]: ${msg_}" + if [ "${log_type_}" = "INFO" ]; then + echo "${log_format_}" + elif [ "${log_type_}" = "WARNING" ]; then + echo "${log_format_}" + elif [ "${log_type_}" = "ERROR" ]; then + echo "${log_format_}" + elif [ "${log_type_}" = "DEBUG" ]; then + echo "${log_format_}" 1> /dev/null + fi +} + +# 返回列表长度 +__length_list() { + local list="$1" + local var="$2" + local list_item + local cnt=0 + + for list_item in ${list}; do + cnt=$((cnt+1)) + done + + eval "${var}=\"${cnt}\"" +} + +# 获取列表索引值 +__index_list() { + local list="$1" + shift + local list_item + local cnt=0 + + if [ $# -eq 0 ]; then + return 0 + fi + + for list_item in ${list}; do + if [ ${1} -eq ${cnt} ]; then + eval "${2}=\"${list_item}\"" + shift 2 + if [ $# -eq 0 ]; then + return 0 + fi + fi + cnt=$((cnt+1)) + done + + return 0 +} + +# 从列表中移除一项 +__remove_item_in_list() { + local to_removed="$1" + shift + local list="$*" + local list_item + local new_list + + for list_item in ${list}; do + if [ "${to_removed}" != "${list_item}" ]; then + if [ "${new_list}" = "" ]; then + new_list="${list_item}" + else + new_list="${new_list} ${list_item}" + fi + fi + done + echo "${new_list}" +} + +# 元素是否在列表中 +__item_in_list() { + local _outvar="$1" + local _item="$2" + shift 2 + local _list_item + local _matched="false" + + for _list_item in $*; do + if [ "${_item}" = "${_list_item}" ]; then + _matched="true" + break + fi + done + eval "${_outvar}=\"${_matched}\"" +} + +# 反转列表 +__reverse_list() { + local _outvar="$1" + local _list="$2" + local _new_list="" + local _list_item + + for _list_item in ${_list}; do + if [ "${_new_list}" = "" ]; then + _new_list="${_list_item}" + else + _new_list="${_list_item} ${_new_list}" + fi + done + eval "${_outvar}=\"${_new_list}\"" +} + +# 修改各文件及目录的属性 +change_own() { + local recursive="$3" + local option="" + local username="${USERNAME}" + local usergroup="${USERGROUP}" + if [ "$2" != "NA" ]; then + if [ "${recursive}" = "true" ]; then + option="-R" + fi + eval chown ${option} -h \"$2\" \"$1\" + if [ $? -ne 0 ]; then + log "ERROR" "$1 chown failed!" + return 1 + fi + fi +} + +# 获取install_for_all文件权限 +get_install_for_all_mod() { + local _outvar="$1" + local _mod="$2" + local _new_mod _other_mod + + _new_mod="${_mod%?}" + _other_mod="${_new_mod#${_new_mod%?}}" + _other_mod="$(($_other_mod & 5))" # other权限位移除写权限,仅支持普通用户运行 + + eval "${_outvar}=\"${_new_mod}${_other_mod}\"" +} + +# 修改各文件及目录的权限 +change_mod() { + local mod="$2" + local install_for_all="$3" + local recursive="$4" + local option="" new_mod + # 对于软连接,可能目标文件还没有拷贝进来,导致无法修改mod,这里过滤掉软连接 + if [ -L "$1" ]; then + return 0 + fi + if [ "$2" != "NA" ]; then + if [ "${recursive}" = "true" ]; then + option="-R" + fi + # 如果设置了install_for_all,则安装时other权限跟group权限对齐 + if [ "${install_for_all}" = "y" ]; then + get_install_for_all_mod new_mod "$mod" + chmod ${option} "${new_mod}" "$1" + else + chmod ${option} "$2" "$1" + fi + if [ $? -ne 0 ]; then + log "ERROR" "$1 chmod failed!" + return 1 + fi + fi + return 0 +} + +# 获取文件权限 +get_file_mod() { + local _outvar="$1" + local _options="" _ret + shift + + while true; do + case "$1" in + -L|--dereference) + _options="${_options} $1" + shift + ;; + *) + break + ;; + esac + done + + local _path="$1" + local _result + + _result="$(stat ${_options} -c %a "${_path}")" + _ret="$?" && [ $_ret -ne 0 ] && return $_ret + eval "${_outvar}=\"${_result}\"" +} + +# 检查路径是否为绝对路径 +__check_abs_path() { + local path="$1" + + if [ "${path#/}" != "${path}" ]; then + is_abs_path="true" + else + is_abs_path="false" + fi +} + +__set_abs_path() { + local install_path="$1" + local path="$2" + local varname="$3" + local is_abs_path + + __check_abs_path "${path}" + if [ "${is_abs_path}" != "true" ]; then + eval "${varname}=\"${install_path}/${path}\"" + else + eval "${varname}=\"${path}\"" + fi +} + +# 创建目录 +make_dir() { + local path="$1" + mkdir -p "${path}" + if [ $? -ne 0 ]; then + log "ERROR" "${path} mkdir failed!" + exit 1 + fi + return 0 +} + +# 检查install_path在docker_root之中 +check_install_path_in_docker_root() { + local install_path="$1" + local docker_root="$2" + + echo "${install_path}" | grep "^${docker_root}" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "ERROR" "check install path ${install_path} in docker root ${docker_root} failed!" + return 1 + fi + return 0 +} + +# 移除路径右侧斜线(/) +rstrip_path() { + local _outvar="$1" + local _path="$2" + + _path="$(echo "${_path}" | sed "s/\/\+\$//g")" + eval "${_outvar}=\"${_path}\"" +} + +# 包是否在tools目录下 +is_package_under_tools() { + local _outvar="$1" + local _package="$2" + local _result_iput="false" + + if [ "${_package}" = "aoe" ] || [ "${_package}" = "nca" ] || [ "${_package}" = "amct_acl" ] || [ "${_package}" = "ncs" ]; then + _result_iput="true" + fi + + eval "${_outvar}=\"${_result_iput}\"" +} + +# 获取包目录名 +get_package_dir() { + local _outvar="$1" + local _package="$2" + local _is_under_tools _result + + is_package_under_tools "_is_under_tools" "${_package}" + if [ "${_is_under_tools}" = "true" ]; then + _result="tools" + else + _result="" + fi + eval "${_outvar}=\"${_result}\"" +} + +# 获取包目录路径 +get_package_dirpath() { + local _outvar="$1" + local _package="$2" + local _is_under_tools _result + + is_package_under_tools "_is_under_tools" "${_package}" + if [ "${_is_under_tools}" = "true" ]; then + _result="tools/${_package}" + else + _result="${_package}" + fi + eval "${_outvar}=\"${_result}\"" +} + +# 获取包ascend_install.info路径 +get_package_install_info() { + local _outvar="$1" + local _install_path="$2" + local _version_dir="$3" + local _package="$4" + local _package_dirpath="" + + eval "${_outvar}=\"\"" + + get_package_dirpath "_package_dirpath" "${_package}" + + eval "${_outvar}=\"${_install_path}/${_version_dir}/${_package_dirpath}/ascend_install.info\"" +} + +# 获取包version.info路径 +get_package_version_info() { + local _outvar="$1" + local _install_path="$2" + local _version_dir="$3" + local _package="$4" + local _package_dirpath="" + + eval "${_outvar}=\"\"" + + get_package_dirpath "_package_dirpath" "${_package}" + + eval "${_outvar}=\"${_install_path}/${_version_dir}/${_package_dirpath}/version.info\"" +} + +# 获取包filelist.csv路径 +get_package_filelist() { + local _outvar="$1" + local _install_path="$2" + local _version_dir="$3" + local _package="$4" + local _package_dirpath="" + + eval "${_outvar}=\"\"" + + get_package_dirpath "_package_dirpath" "${_package}" + + eval "${_outvar}=\"${_install_path}/${_version_dir}/${_package_dirpath}/script/filelist.csv\"" +} + +# 获取包install_common_parser.sh路径 +get_package_install_common_parser() { + local _outvar="$1" + local _install_path="$2" + local _version_dir="$3" + local _package="$4" + local _package_dirpath="" + + eval "${_outvar}=\"\"" + + get_package_dirpath "_package_dirpath" "${_package}" + + eval "${_outvar}=\"${_install_path}/${_version_dir}/${_package_dirpath}/script/install_common_parser.sh\"" +} + +# 获取latest_manager的install_common_parser.sh路径 +get_latest_manager_install_common_parser() { + local _outvar="$1" + local _install_path="$2" + local _latest_dir="$3" + + eval "${_outvar}=\"${_install_path}/${_latest_dir}/var/manager/install_common_parser.sh\"" +} + +# 获取包script目录路径 +get_package_script_dirpath() { + local _outvar="$1" + local _install_path="$2" + local _version_dir="$3" + local _package="$4" + local _package_dirpath="" + + eval "${_outvar}=\"\"" + + get_package_dirpath "_package_dirpath" "${_package}" + + eval "${_outvar}=\"${_install_path}/${_version_dir}/${_package_dirpath}/script\"" +} + +# 检查参数不为空 +check_param_not_empty() { + local name="$1" + local error_msg="$2" + local value + + eval "value=\"\${${name}}\"" + + if [ "${value}" = "" ]; then + comm_log "ERROR" "$2" + return 1 + fi + + return 0 +} + +# 检查文件存在 +check_file_exists() { + local path="$1" + local error_msg="$2" + + if [ ! -f "${path}" ]; then + comm_log "ERROR" "$2" + return 1 + fi + + return 0 +} + +# 检查返回值是否为0 +check_ret_error() { + local ret="$1" + local msg="$2" + + if [ ${ret} -ne 0 ]; then + comm_log "ERROR" "${msg}" + return ${ret} + fi + + return 0 +} + +# 检查返回值是否为0 +check_ret_warning() { + local ret="$1" + local msg="$2" + + if [ ${ret} -ne 0 ]; then + comm_log "WARNING" "${msg}" + return ${ret} + fi + + return 0 +} + +# 获取真实路径 +get_realpath() { + local _outvar="$1" + local _path_gr="$2" + + _path_gr="$(readlink -f "${_path_gr}")" + eval "${_outvar}=\"${_path_gr}\"" +} + +# 检查返回值是否为0 +cleanup_if_error() { + local ret="$1" + local cleanup="$2" + + if [ ${ret} -ne 0 ]; then + eval "${cleanup}" + return ${ret} + fi + + return 0 +} + +# 获取临时目录 +get_tmp_root() { + local _outvar="$1" + local _result_gtr + + if [ -d "${HOME}" ]; then + _result_gtr="${HOME}" + elif [ $(id -u) -eq 0 ] && [ -d "/root" ]; then + _result_gtr="/root" + else + _result_gtr="${PWD}" + fi + + eval "${_outvar}=\"${_result_gtr}\"" + return 0 +} + +# 获取临时文件 +get_tmp_file() { + local _outvar="$1" + local _filename="$2" + local _tmp_file_gtf _result + + get_tmp_root "_tmp_file_gtf" + + _result=$(mktemp "$_tmp_file_gtf/${_filename}_XXXXXX") + check_ret_warning "$?" "mktemp $_tmp_file_gtf/${_filename}_XXXXXX failed." + ret="$?" && [ $ret -ne 0 ] && return $ret + + eval "${_outvar}=\"${_result}\"" + return 0 +} + +# 获取包架构 +get_scene_arch() { + local _outvar="$1" + local _scene_filepath="$2" + local _result + + _result="$(grep "^arch=" "${_scene_filepath}" | cut -d= -f2-)" + eval "${_outvar}=\"${_result}\"" +} + +# 打包feature参数 +pack_feature_param() { + local _outvar="$1" + local _feature_type="$2" + local _feature_exclude_all="$3" + local _chip="$4" + + eval "${_outvar}=\"${_feature_type} ${_feature_exclude_all} ${_chip}\"" +} + +# 解包feature参数 +# 注意,调用解包时参数不可加引号 +unpack_feature_param() { + local _feature_type_var="$1" + local _feature_exclude_all_var="$2" + local _chip_var="$3" + shift 3 + eval "${_feature_type_var}=\"${1}\"" + eval "${_feature_exclude_all_var}=\"${2}\"" + eval "${_chip_var}=\"${3}\"" +} + +# 展开version.info文件中参数 +expand_version_file() { + if [ "${VERSION_FILE}" = "" ]; then + return 0 + fi + get_version "VERSION" "${VERSION_FILE}" + get_version_dir "VERSION_DIR" "${VERSION_FILE}" +} + +# 提取第一项 +extract_1st() { + local _outvar="$1" + eval "${_outvar}=\"$2\"" +} + +# 提取第二项 +extract_2nd() { + local _outvar="$1" + eval "${_outvar}=\"$3\"" +} + +# 路径转为sed正则表达式 +path_to_regex() { + local _outvar="$1" + local _path="$2" + local _reslut_ptr="$(echo "${_path}" | sed "s#\/#\\\/#g")" + + eval "${_outvar}=\"${_reslut_ptr}\"" +} + +# 设置默认值 +set_default() { + local _outvar="$1" + local _input="$2" + local _default="$3" + + if [ "${_input}" = "" ]; then + eval "${_outvar}=\"${_default}\"" + else + eval "${_outvar}=\"${_input}\"" + fi +} + +# 标准化feature参数 +# 输入的feature参数中,如果有all字段(表示安装所有feature) +# 则将feature参数重置为all,在后续流程中安装所有feature +# 卸载流程中,feature与chip强制为all,保证卸载掉block中的所有文件 +normalize_feature() { + local _outvar="$1" + local _feature_nf="$2" + local _operation="$3" + + if [ "$_operation" = "uninstall" ]; then + eval "${_outvar}=\"all\"" + return 0 + fi + + if [ "$_feature_nf" = "" ]; then + eval "${_outvar}=\"all\"" + return 0 + fi + + case "${_feature_nf}" in + all,*) + _feature_nf="all" + ;; + *,all) + _feature_nf="all" + ;; + *,all,*) + _feature_nf="all" + ;; + esac + + eval "${_outvar}=\"${_feature_nf}\"" +} + +# 删除软连接 +remove_softlink_icp() { + local softlink="$1" + + if [ "${softlink}" = "" ]; then + return 0 + fi + + if [ "${softlink}" != "NA" ] && [ -L "${softlink}" ]; then + rm -f "${softlink}" + if [ $? -ne 0 ]; then + log "ERROR" "remove ${softlink} failed!" + return 1 + fi + fi + return 0 +} + +#移除文件 +remove_file() { + local target="$1" + local softlink="$2" + local ret + if [ -e "${target}" ] || [ -L "${target}" ]; then + rm -f "${target}" + if [ $? -ne 0 ]; then + log "ERROR" "remove ${target} failed!" + return 1 + fi + fi + remove_softlink_icp "${softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 创建文件夹 +create_folder() { + local install_path="$1" + local target="$2" + local softlinks_str="$3" + local ret target_abs + + __set_abs_path "${install_path}" "${target}" "target_abs" + + if [ ! -d "${target_abs}" ]; then + make_dir "${target_abs}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + change_mod "${target_abs}" "${RESET_MOD}" "" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + if [ "${softlinks_str}" != "NA" ]; then + create_softlink_by_install_path "${install_path}" "${target}" "${softlinks_str}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + return 0 +} + +# 创建目录 +create_dirs() { + local install_path="$1" + local line="$2" + local target + local target_abs + local softlinks_str + local ret + + __index_list "${line}" 1 "target" 4 "softlinks_str" + + __set_abs_path "${install_path}" "${target}" "target_abs" + + if [ -L "${target_abs}" ] ; then + rm -f "${target_abs}" + log "WARNING" "${target_abs} is an existing soft-link, deleted." + fi + create_folder "${install_path}" "${target}" "${softlinks_str}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + return 0 +} + +# 修改目录的权限和属组 +reset_mod_dirs() { + local install_path="$1" + local line="$2" + local mod + local target + local target_abs + local is_abs_path ret + + __index_list "${line}" 1 "target" + + __set_abs_path "${install_path}" "${target}" "target_abs" + + # 目录不存在时跳过 + if [ ! -d "${target_abs}" ]; then + return 0 + fi + # 只处理目录,没有处理目录的软链接 + change_mod "${target_abs}" "${RESET_MOD}" "" "false" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 递归修改目录的权限和属组 +reset_mod_dirs_recursive() { + local install_path="$1" + local line="$2" + local mod + local target + local target_abs + local is_abs_path ret + + __index_list "${line}" 1 "target" + + __set_abs_path "${install_path}" "${target}" "target_abs" + + # 目录不存在时跳过 + if [ ! -d "${target_abs}" ]; then + return 0 + fi + # 只处理目录,没有处理目录的软链接 + change_mod "${target_abs}" "${RESET_MOD}" "" "true" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +__unpack_softlinks() { + local softlinks_str="$1" + local varname="$2" + local item + local temp + OLD_IFS="${IFS}" + IFS=";" + temp="" + for item in ${softlinks_str}; do + if [ "${temp}" = "" ]; then + temp="${item}" + else + temp="${temp} ${item}" + fi + done + IFS="${OLD_IFS}" + + eval "${varname}=\"${temp}\"" +} + +#移除文件夹 +remove_dir_icp() { + if [ -e "$1" ] || [ -L "$1" ]; then + rm -fr "$1" + if [ $? -ne 0 ]; then + log "ERROR" "$1 remove failed!" + return 1 + fi + fi + return 0 +} + +# 创建软链时,移除存在的目录 +remove_exists_dir_in_create_softlink() { + local dirpath="$1" + + if [ -d "${dirpath}" ] && [ ! -L "${dirpath}" ]; then + log "WARNING" "${dirpath} is an existing directory in create softlink, deleted." + change_mod "${dirpath}" "700" "n" "true" + remove_dir_icp "${dirpath}" + fi +} + +# 创建绝对软链接 +create_softlink_icp_absolute() { + local src_path="$1" + local dst_path="$2" + + remove_exists_dir_in_create_softlink "${dst_path}" + ln -sfn "${src_path}" "${dst_path}" + if [ $? -ne 0 ]; then + log "ERROR" "create softlink absolute from ${src_path} to ${dst_path} failed!" + return 1 + fi + return 0 +} + +# 该函数与common_func.inc脚本中的相同 +# install_common_parser.sh不一定能source到common_func.inc(原因见source common_func.inc的注释) +# 所以这里需要重复定义 +create_softlink_icp_relative() { + local src_path="$1" + local dst_path="$2" + local source="top${src_path}" + local target="top${dst_path}" + + # 若变量内容从尾向前的数据符合,则将符合的最短数据删除 + local common="${target%/*}" + # 若变量内容从头开始的数据符合,则将符合的最短数据删除 + local forward="${source#"$common"/}" + + local result="" + + while [ "${forward}" = "${source}" ]; do + common="$(dirname "$common")" + forward="${source#"$common"/}" + result="../${result}" + done + + result="${result}${forward}" + + remove_exists_dir_in_create_softlink "${dst_path}" + ln -sfn "${result}" "${dst_path}" + if [ $? -ne 0 ]; then + log "ERROR" "create softlink relative from ${src_path} to ${dst_path} failed!" + return 1 + fi + return 0 +} + +# 创建软连接 +create_softlink_by_install_path() { + local install_path="$1" + local target="$2" + local softlinks_str="$3" + local softlinks softlink + local target_abs + local softlink_abs + local is_abs_path + local ret + + if [ "${softlinks_str}" = "NA" ]; then + return 0 + fi + + __unpack_softlinks "${softlinks_str}" "softlinks" + + for softlink in ${softlinks}; do + __check_abs_path "${target}" + if [ "${is_abs_path}" = "true" ]; then + __set_abs_path "${install_path}" "${softlink}" "softlink_abs" + create_softlink_icp_absolute "${target}" "${softlink_abs}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + continue + fi + + __check_abs_path "${softlink}" + if [ "${is_abs_path}" = "true" ]; then + __set_abs_path "${install_path}" "${target}" "target_abs" + create_softlink_icp_absolute "${target_abs}" "${softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + continue + fi + + create_softlink_icp_relative "${install_path}/${target}" "${install_path}/${softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + done + + return 0 +} + +# 创建软链接。icp后缀为避免重名 +create_softlink_icp() { + local options="" + local is_relative="false" + + while true; do + case "$1" in + -r|--relative) + is_relative="true" + shift + ;; + -*) + log "ERROR" "unsupported option $1 in create softlink icp!" + return 1 + ;; + *) + break + ;; + esac + done + + local src_path="$1" + local dst_path="$2" + + if [ "${is_relative}" = "true" ]; then + create_softlink_icp_relative "${src_path}" "${dst_path}" + else + create_softlink_icp_absolute "${src_path}" "${dst_path}" + fi +} + +# 修改权限和属组 +change_mod_and_own(){ + local target="$1" + local mod="$2" + local own="$3" + local install_for_all="$4" + local recursive="$5" + local ret + + change_mod "${target}" "${mod}" "${install_for_all}" "${recursive}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_own "${target}" "${own}" "${recursive}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 修改目录的权限和属组 +change_mod_and_own_dirs() { + local install_path="$1" + local line="$2" + local target + local mod + local own + local is_abs_path + + __index_list "${line}" 1 "target" 2 "mod" 3 "own" + + __check_abs_path "${target}" + if [ "${is_abs_path}" != "true" ]; then + target="${install_path}/${target}" + fi + if [ ! -d "${target}" ]; then + return 0 + fi + # 只处理目录,没有处理目录的软链接 + change_mod_and_own "${target}" "${mod}" "${own}" "${INSTALL_FOR_ALL}" "false" +} + +# 创建stash_mod.txt文件 +create_stash_mod() { + local install_path="$1" + rm -f "${install_path}/${STASH_MOD_PATH}" + touch "${install_path}/${STASH_MOD_PATH}" + chmod ${STASH_FILE_MOD} "${install_path}/${STASH_MOD_PATH}" +} + +# 删除stash_mod.txt文件 +remove_stash_mod() { + local install_path="$1" + rm -f "${install_path}/${STASH_MOD_PATH}" +} + +# 修改目录的权限和属组 +restore_stash_mod() { + local install_path="$1" + local line="$2" + local target + local target_abs + local mod + local is_abs_path ret + + __index_list "${line}" 0 "target" 1 "mod" + + __set_abs_path "${install_path}" "${target}" "target_abs" + + # 目录不存在时跳过 + if [ ! -d "${target_abs}" ]; then + return 0 + fi + # 只处理目录,没有处理目录的软链接 + change_mod "${target_abs}" "${mod}" "${INSTALL_FOR_ALL}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 修改目录的权限,暂存原文件权限 +reset_mod_dirs_with_stash_mod() { + local install_path="$1" + local line="$2" + local mod + local target + local target_abs + local is_abs_path ret + + __index_list "${line}" 1 "target" + + __set_abs_path "${install_path}" "${target}" "target_abs" + + # 目录不存在时跳过 + if [ ! -d "${target_abs}" ]; then + return 0 + fi + + get_file_mod "mod" "${target_abs}" + echo "${target}:${mod}" >> "${install_path}/${STASH_MOD_PATH}" + + # 只处理目录,没有处理目录的软链接 + change_mod "${target_abs}" "${RESET_MOD}" "" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 删除软连接列表 +remove_softlinks() { + local install_path="$1" + local softlinks_str="$2" + local softlinks softlink softlink_abs ret + + __unpack_softlinks "${softlinks_str}" "softlinks" + + for softlink in ${softlinks}; do + __set_abs_path "${install_path}" "${softlink}" "softlink_abs" + remove_softlink_icp "${softlink_abs}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + done + return 0 +} + +# 删除安装文件夹 +remove_install_dirs() { + local install_path="$1" + local line="$2" + local target softlinks_str is_abs_path + + __index_list "${line}" 1 "target" 4 "softlinks_str" + + if [ "${target}" != "NA" ]; then + __check_abs_path "${target}" + if [ "${is_abs_path}" != "true" ]; then + target="${install_path}/${target}" + fi + if [ -d "${target}" ]; then + # 不同的blocks中,可能配置相同的dir_info。目录不为空时不删除。 + if [ "$(ls -A "${target}")" != "" ]; then + return 0 + fi + remove_dir_icp "${target}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + if [ "${softlinks_str}" != "NA" ]; then + remove_softlinks "${install_path}" "${softlinks_str}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + fi + return 0 +} + +# 获取所有的blocks +get_blocks_info() { + local _outvar="$1" + local _install_path="$2" + local _result _db_filepath="${_install_path}/${PKG_DB_INFO_RELPATH}" + + if [ ! -f "${_db_filepath}" ]; then + return 0 + fi + _result="$(cut -d'|' -f1 "${_db_filepath}" | xargs)" + eval "${_outvar}=\"${_result}\"" +} + +# 列表转为正则表达式 +trans_list_to_regex() { + local _outvar="$1" + local _value="$2" + # 移除右侧空白符,mawk无法编译右侧存在空白符时的正则表达式,如:^(EngineeringCommon|)$ + local _result="$(echo "$_value" | sed 's/\s\+$//g' | sed 's/ /|/g' | xargs printf "^(%s)$")" + eval "${_outvar}=\"${_result}\"" +} + +parse_filelist_core() { + awk -F, '{ print $3,$4,$6,$7,$9,$12,$13,$14,$15 }' +} + +# 过滤公共路径条目 +filter_common_dirs() { + awk -F, ' + $11 == "Y" { + print $0 + } + $11 == "YY" { + print $1 "," $2 "," $3 "," $4 "," $5 "," $6 "," $7 "," $8 ",NA," $10 "," $11 "," $12 "," $13 "," $14 "," $15 "," $16 + } + ' +} + +# 过滤包内软链 +filter_pkg_inner_softlink() { + awk -F, '$15 != "NA" { print $0 }' +} + +# 过滤块 +filter_blocks() { + local blocks="$1" + local blocks_reg + + trans_list_to_regex "blocks_reg" "$blocks" + awk -F, "\$14 ~ \"$blocks_reg\" {print \$0}" +} + +# 过滤不匹配块 +filterfalse_blocks() { + local blocks="$1" + local blocks_reg + + trans_list_to_regex "blocks_reg" "$blocks" + awk -F, "\$14 !~ \"$blocks_reg\" {print \$0}" +} + +# 过滤操作类型条目 +filter_operate_type() { + local operator_type="$1" + local operator_type_reg + + trans_list_to_regex "operator_type_reg" "$operator_type" + + # ~为部分匹配,正则表达式需要匹配头尾 + awk -F, "\$2 ~ \"$operator_type_reg\" {print \$0}" +} + +# 过滤安装类型条目 +filter_install_type() { + local install_type="$1" + local install_type_reg + + # 注意:特征串不能嵌套,否则会错误匹配 + if [ "$install_type" != "full" ] && [ "$install_type" != "debug" ]; then + install_type_reg="(all)|($install_type)" + else + install_type_reg="(all)|(docker)|(devel)|(run)" + fi + + awk -F, "\$8 ~ \"$install_type_reg\" {print \$0}" +} + +# 过滤特性参数 +filter_feature_param() { + local feature_param="$1" + local feature_type + local feature_exclude_all # feature是否为排除公共all文件 + local chip chip_list # 芯片类型 + local feature_list feature_type_list + + unpack_feature_param "feature_type" "feature_exclude_all" "chip" ${feature_param} + + if [ "$feature_type" != "all" ]; then + feature_list="$(echo $feature_type | tr ',' ' ')" + if [ "${feature_exclude_all}" = "y" ]; then + feature_type_list="${feature_list}" + else + feature_type_list="comm ${feature_list}" + fi + else + feature_type_list="all" + fi + + if [ "$chip" != "all" ]; then + chip_list="all $(echo $chip | tr ',' ' ')" + else + chip_list="all" + fi + + # filelist中的feature为all,表示所有场景下都安装这个文件 + # 输入参数中的feature为all,表示安装所有的feature + awk -v feature_type_list="${feature_type_list}" \ + -v chip_list="${chip_list}" ' + BEGIN { + FS= "," + split(feature_type_list, input_feature_type_arr, " ") + split(chip_list, input_chip_arr, " ") + } + + function match_feature_type(features_str) { + if (feature_type_list == "all") { + return 1 + } + matched_feature_type_tmp=0 + split(features_str, features, ";") + for(i in features) + { + for(j in input_feature_type_arr) { + if(input_feature_type_arr[j] == features[i]) { + matched_feature_type_tmp = 1 + break; + } + } + } + return matched_feature_type_tmp + } + + function match_chip(chip_str) { + if (chip_list == "all") { + return 1 + } + matched_chip_tmp=0 + split(chip_str, chips, ";") + for(i in chips) + { + for(j in input_chip_arr) { + if(input_chip_arr[j] == chips[i]) { + matched_chip_tmp = 1 + break; + } + } + } + return matched_chip_tmp + } + + { + matched_feature_type = match_feature_type($10); + if (matched_feature_type == 0) next; + + matched_chip = match_chip($16) + if (matched_chip == 0) next + + print $0 + }' +} + +# 读取fileist的第2行到最后行 +tail_filelist() { + local filelist_path="$1" + tail -n +2 "$filelist_path" +} + +# 解析filelist.csv脚本 +parse_filelist() { + local install_type="$1" + local operate_type="$2" + local filelist_path="$3" + local feature_param="$4" + local filter_type="$5" + local blocks="$6" + + if [ ! -f "$filelist_path" ]; then + log "ERROR" "filelist $filelist_path does not exist!" + exit 1 + fi + + # 注意:这里的filelist需要是全局变量。其它函数(如add_filelist_blocks_info)会引用这个变量。 + filelist=$( + parse_filelist_v2 "$install_type" "$operate_type" "$filelist_path" "$feature_param" \ + "$filter_type" "$blocks" + ) +} + +# 解析filelist.csv脚本 +parse_filelist_v2() { + local install_type="$1" + local operate_type="$2" + local filelist_path="$3" + local feature_param="$4" + local filter_type="$5" + local blocks="$6" + local filter_cmds="" + + if [ "$operate_type" != "all" ]; then + filter_cmds="$filter_cmds | filter_operate_type \"$operate_type\"" + fi + if printf "%s" "$filter_type" | grep -Eq "\"; then + filter_cmds="$filter_cmds | filter_common_dirs" + fi + if printf "%s" "$filter_type" | grep -Eq "\"; then + filter_cmds="$filter_cmds | filter_pkg_inner_softlink" + fi + if printf "%s" "$filter_type" | grep -Eq "\|\" && [ "$blocks" != "" ]; then + filter_cmds="$filter_cmds | filterfalse_blocks \"$blocks\"" + fi + if printf "%s" "$filter_type" | grep -Eq "\" && [ "$blocks" != "" ]; then + filter_cmds="$filter_cmds | filter_blocks \"$blocks\"" + fi + + tail_filelist "$filelist_path" \ + | filter_install_type "$install_type" \ + | filter_feature_param "$feature_param" \ + | eval cat $filter_cmds \ + | parse_filelist_core +} + + +pack_exec_params() { + local _outvar="$1" + local _exec_mode="$2" + + eval "${_outvar}=\"${_exec_mode}\"" +} + + +# 迭代filelist中的条目,执行操作 +foreach_filelist_exec() { + local filelist="$1" + local sort_filelist="$2" + local exec_mode="$3" + local exec_func="$4" + local install_path="$5" + local ret=0 tmp_ret exec_params + shift 5 + + pack_exec_params "exec_params" "${exec_mode}" + + if [ "${sort_filelist}" = "reverse" ]; then + # 对第二列文件路径做倒序排列,保证先删除子文件夹,再删除父文件夹 + # 不可以使用echo "${filelist}" + # 在dash中会消耗\\$username:\\$usergroup中的一个反斜线(bash与busybox的sh无此问题) + # 需要使用here document,防止shell的解析过程 + filelist=$(sort -k2,2 -b -r < /dev/null + else + log "ERROR" "sort_type param wrong! sort_type is ${sort_type}, exec_func is ${exec_func}" + exit 1 + fi + + while read line; do + array=${line} + __length_list "${array}" "len_array" + if [ ${len_array} -eq 0 ]; then + continue + fi + "${exec_func}" "${install_path}" "${line}" + tmp_ret="$?" && [ ${tmp_ret} -ne 0 ] && ret="${tmp_ret}" + done << EOF +${stashmod_list} +EOF + + return $ret +} + +# 创建目录并且设置权限 +make_dir_with_permission() { + local path="$1" + local mod="$2" + local username="$3" + local usergroup="$4" + local install_for_all="$5" + local ret + + make_dir "${path}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + change_mod "${path}" "${mod}" "${install_for_all}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + change_own "${path}" "${username}:${usergroup}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# blocks转换为db.info配置 +blocks_to_db_item() { + local package="$1" + local version_dir="$2" + + xargs printf "%s|[$package:$version_dir]\n" +} + +# 折叠第2个参数 +# 需要保证输入数据第1个参数已排序 +fold_2() { + local fs="$1" + local concat="$2" + local options="" + + if [ "$fs" != "" ]; then + options="-F$fs" + fi + + awk $options -v CONCAT="$concat" ' + NR == 1 { + field1 = $1 + field2 = $2 + } + NR != 1 { + if (field1 == $1) { + field2 = field2 CONCAT $2 + } else { + print field1 FS field2 + field1 = $1 + field2 = $2 + } + } + END { + if (field1) { + print field1 FS field2 + } + }' +} + +# 折叠第3个参数,保持第2个参数 +# 需要保证输入数据第1个参数已排序 +fold_3_keep_2() { + local fs="$1" + local concat="$2" + local options="" + + if [ "$fs" != "" ]; then + options="-F$fs" + fi + + awk $options -v CONCAT="$concat" ' + NR == 1 { + field1 = $1 + field2 = $2 + field3 = $3 + } + NR != 1 { + if (field1 == $1) { + field3 = field3 CONCAT $3 + } else { + print field1 FS field2 FS field3 + field1 = $1 + field2 = $2 + field3 = $3 + } + } + END { + if (field1) { + print field1 FS field2 FS field3 + } + }' +} + +# 根据第1列排序 +sort_1() { + local sep="$1" + local options="" + if [ "$sep" != "" ]; then + options="-t$sep" + fi + sort $options -k1,1 -s +} + +# 显示3,4列有差异的条目 +show_diff_3_4() { + awk '$3 != $4 { print $0 }' +} + +# 显示具有最少列数的条目 +show_min_nf() { + local min_nf="$1" + awk -v MIN_NF="$min_nf" 'NF >= MIN_NF { print $0 }' +} + +# 选取第3,2,1列 +select_fields_3_2_1() { + awk '{print $3, $2, $1}' +} + +# 选取第1列 +select_fields_1() { + awk '{print $1}' +} + +# 删除db.info配置 +del_db_items() { + local package="$1" + local version_dir="$2" + + sed "s/\\[$package:$version_dir\\]//g; /|\$/d" +} + +# 保留块最后一个配置 +# 输出:第1列(块),第2列(包名),第3列(版本目录) +remain_db_last_item() { + awk -F '[|:\\[\\]]+' '{ print $1, $(NF-2), $(NF-1) }' +} + +# 移除空白行 +remove_blank_line() { + sed '/^$/d' +} + +# 保证文件权限 +ensure_permission() { + local path="$1" + local mod="$2" + local username="$3" + local usergroup="$4" + local install_for_all="$5" + + change_mod "$path" "$mod" "$install_for_all" + ret=$? && [ $ret -ne 0 ] && return $ret + + change_own "$path" "$username:$usergroup" + ret=$? && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 创建文件 +touch_file() { + local path="$1" + local mod="$2" + local username="$3" + local usergroup="$4" + local install_for_all="$5" + local ret + + touch "$path" + ret=$? && [ $ret -ne 0 ] && return $ret + + ensure_permission "$path" "$mod" "$username" "$usergroup" "$install_for_all" + ret=$? && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 保证文件存在 +ensure_file() { + local path="$1" + local mod="$2" + local username="$3" + local usergroup="$4" + local install_for_all="$5" + local ret + + if [ ! -f "$path" ]; then + touch_file "$path" "$mod" "$username" "$usergroup" "$install_for_all" + ret=$? && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# 写文本文件 +write_text() { + local content="$1" + local filepath="$2" + + printf "%s\n" "$content" > "$filepath" +} + +# 修改文件权限并操作 +with_chmod() { + local path="$1" + local mod="$2" + local origin_mod ret + shift 2 + + origin_mod="$(stat -L -c "%a" "$path")" + chmod "$mod" "$path" + "$@" + ret="$?" + chmod "$origin_mod" "$path" + + return $ret +} + +# filelist中所有公共目录的块 +all_common_dirs_blocks_in_filelist() { + local install_type="$1" + local filelist_path="$2" + local feature_param="$3" + + parse_filelist_v2 "$install_type" "all" "$filelist_path" "$feature_param" "filter_common_dirs" "" \ + | cut -d' ' -f8 | sort | uniq +} diff --git a/scripts/package/common/sh/common_installer.inc b/scripts/package/common/sh/common_installer.inc new file mode 100644 index 0000000000000000000000000000000000000000..dfe258a0561367384a78cdfc1af0c6759f8b9538 --- /dev/null +++ b/scripts/package/common/sh/common_installer.inc @@ -0,0 +1,55 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +# 通知latest管理器创建版本软链 +notify_latest_manager_create_version_softlink() { + local curpath install_path version_dir var_path + + set_comm_log "Notifier" + + curpath="$(dirname $(readlink -f "${BASH_SOURCE:-$0}"))" + install_path="$(readlink -f "$curpath/..")" + version_dir="$(basename "$curpath")" + var_path="$install_path/$LATEST_DIR/var" + + if [ ! -f "$var_path/manager.sh" ]; then + comm_log "ERROR" "$var_path/manager.sh doesn't exist!" + exit 2 + fi + + if ! "$var_path/manager.sh" --version-dir "$version_dir" create_version_softlink; then + comm_log "ERROR" "create version softlink failed!" + exit 1 + fi + return 0 +} + +# 通知latest管理器删除latest软链 +notify_latest_manager_remove_latest_softlink() { + local curpath install_path var_path + + set_comm_log "Notifier" + + curpath="$(dirname $(readlink -f "${BASH_SOURCE:-$0}"))" + install_path="$(readlink -f "$curpath/..")" + var_path="$install_path/$LATEST_DIR/var" + + if [ ! -f "$var_path/manager.sh" ]; then + comm_log "ERROR" "$var_path/manager.sh doesn't exist!" + exit 2 + fi + + if ! "$var_path/manager.sh" remove_latest_softlink; then + comm_log "ERROR" "remove latest softlink failed!" + exit 1 + fi + return 0 +} diff --git a/scripts/package/common/sh/common_interface.bash b/scripts/package/common/sh/common_interface.bash new file mode 100644 index 0000000000000000000000000000000000000000..805dc990a62782f3cc028e789edba7330c61c081 --- /dev/null +++ b/scripts/package/common/sh/common_interface.bash @@ -0,0 +1,61 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +mk_custom_path() { + if [ $(id -u) -eq 0 ]; then + return 0 + fi + local _custom_path_file="$1" + while read line || [ -n "$line" ] + do + local _custom_path="$(echo "$line" | cut --only-delimited -d= -f2)" + if [ -z "$_custom_path" ]; then + continue + fi + eval "_custom_path=$_custom_path" + if [ ! -d "$_custom_path" ]; then + mkdir -p "$_custom_path" + if [ $? -ne 0 ]; then + cur_date="$(date +"%Y-%m-%d %H:%M:%S")" + echo "[Common] [$cur_date] [ERROR]: create $_custom_path failed." + return 1 + fi + fi + done < $_custom_path_file + return 0 +} + +py_version_check(){ + local pyver_set="3.9 3.11" + local cur_date="$(date +"%Y-%m-%d %H:%M:%S")" + which python3 > /dev/null 2>&1 + if [ $? -eq 0 ]; then + local python_version="$(python3 --version 2>&1 | head -n 1)" + local python3_version=$(echo "$python_version" | sed -n 's/.*[^\.0-9]\([0-9]\+\.[0-9]\+\).*/\1/p') + if [ "x$python3_version" != "x" ]; then + for ver in $pyver_set; do + if [ "x$ver" = "x$python3_version" ]; then + return 0 + fi + done + + echo "[Common] [$cur_date] [WARNING]: $python_version is not in Python3.9.x, Python3.11.x." + return 1 + else + echo "[Common] [$cur_date] [WARNING]: $python_version cannot be identified as a standard version, please check manually." + return 1 + fi + else + echo "[Common] [$cur_date] [WARNING]: python3 is not found." + return 1 + fi +} + diff --git a/scripts/package/common/sh/common_interface.csh b/scripts/package/common/sh/common_interface.csh new file mode 100644 index 0000000000000000000000000000000000000000..aef4c47fd7a048db32b82063902ed3ad5a0edfe2 --- /dev/null +++ b/scripts/package/common/sh/common_interface.csh @@ -0,0 +1,37 @@ +#!/bin/csh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +set func_name = "$1" +switch ( "$func_name" ) + case "mk_custom_path": + if ( "`id -u`" == 0 ) then + exit 0 + endif + set file_path = "$2" + foreach line ("` cat $file_path `") + set custom_path = "`echo '$line' | cut --only-delimited -d= -f2`" + if ( "$custom_path" == "" ) then + continue + endif + set custom_path = "` eval echo $custom_path `" + if ( ! -d "$custom_path" ) then + mkdir -p "$custom_path" + if ( $status != 0 ) then + set cur_date = "`date +'%Y-%m-%d %H:%M:%S'`" + echo "[Common] [$cur_date] [ERROR]: create $custom_path failed." + exit 1 + endif + endif + end + breaksw + default: + breaksw +endsw diff --git a/scripts/package/common/sh/common_interface.fish b/scripts/package/common/sh/common_interface.fish new file mode 100644 index 0000000000000000000000000000000000000000..d8e3e5450e90d4030439fd5bb07345da4a29e3ca --- /dev/null +++ b/scripts/package/common/sh/common_interface.fish @@ -0,0 +1,33 @@ +#!/usr/bin/env fish +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +function mk_custom_path + set -l custom_file_path $argv[1] + if test (id -u) -eq 0 + return 0 + end + while read line + set -l _custom_path (echo "$line" | cut --only-delimited -d= -f2) + if test -z $_custom_path + continue + end + set -l _custom_path (eval echo "$_custom_path") + if not test -d $_custom_path + mkdir -p "$_custom_path" + if not test $status -eq 0 + set -l cur_date (date +"%Y-%m-%d %H:%M:%S") + echo "[Common] [$cur_date] [ERROR]: create $_custom_path failed." + return 1 + end + end + end < $custom_file_path + return 0 +end diff --git a/scripts/package/common/sh/install_common_parser.sh b/scripts/package/common/sh/install_common_parser.sh new file mode 100644 index 0000000000000000000000000000000000000000..2cfd88548435f34b5df2a80b8af923b7d58397f5 --- /dev/null +++ b/scripts/package/common/sh/install_common_parser.sh @@ -0,0 +1,2200 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +# run包安装解析公共脚本 +# 解析filelist.csv文件,完成目录创建,文件复制,权限设置,文件删除等操作。 + +# minirc场景下存在使用dash调用该脚本的情况 +#export PS4='+ ${FUNCNAME[0]:+${FUNCNAME[0]}():} ${BASH_SOURCE}:${LINENO}: ' +#set -x +# 总uninstall.sh文件权限 +TOTAL_UNINSTALL_MOD="500" +# db.info文件权限 +DB_INFO_MOD="640" +# 包架构 +PKG_ARCH="UNKNOWN" +# 复制文件是否并发 +PARALLEL="" +# 是否限制并发 +PARALLEL_LIMIT="" +# 控制并发的fifo文件路径 +PARALLEL_FIFO="none" +COPY_COMMAND="cp -rf" +MOVE_COMMAND="mv -f" + +curpath="$(dirname $(readlink -f "${BASH_SOURCE:-$0}"))" + +# 导入公共库 +common_func_v2_path="${curpath}/common_func_v2.inc" +. "${common_func_v2_path}" + +# 导入common_func.inc +# 不一定能source到common_func.inc +# 例如driver包中的install_common_parser.sh与common_func.inc,不在同一个目录下 +# 需要子包整改,才将该if语句移除 +common_func_path="${curpath}/common_func.inc" +if [ -f "${common_func_path}" ]; then + . "${common_func_path}" +fi + +# 导入script_operator.inc +script_operator_path="${curpath}/script_operator.inc" +if [ -f "${script_operator_path}" ]; then + . "${script_operator_path}" +fi + +# 导入version_cfg.inc +version_cfg_path="${curpath}/version_cfg.inc" +if [ -f "${version_cfg_path}" ]; then + . "${version_cfg_path}" +fi + +# 导入multi_version.inc +multi_version_path="${curpath}/multi_version.inc" +if [ -f "${multi_version_path}" ]; then + . "${multi_version_path}" +fi + +# 导入version_compatiable.inc +version_compatiable_path="${curpath}/version_compatiable.inc" +if [ -f "${version_compatiable_path}" ]; then + . "${version_compatiable_path}" +fi + +# 导入config.inc +config_path="${curpath}/config.inc" +if [ -f "${config_path}" ]; then + . "${config_path}" +fi + +# 导入cold_patch.sh +cold_patch_path="${curpath}/cold_patch.sh" +if [ -f "${cold_patch_path}" ]; then + . "${cold_patch_path}" +fi + +# bash执行时需要展开别名 +if [ -n "$BASH_SOURCE" ]; then + shopt -s expand_aliases +fi + +__pkg_in_pkgs() { + local matched + __item_in_list "matched" "$@" + echo "${matched}" +} + +__block_in_blocks() { + __item_in_list "matched" "$@" + echo "${matched}" +} + +# 包列表中移除包 +__remove_pkg_in_pkgs() { + __remove_item_in_list "$@" +} + +# 冒泡排序,O(n**2) +__sort_blocks() { + local blocks="$*" + local block + local sorted_blocks="" + local max + local i=0 + + __length_list "${blocks}" "len_blocks" + + while [ "$i" -lt ${len_blocks} ]; do + max="" + for block in ${blocks}; do + if [ "${block}" \> "${max}" ]; then + max="${block}" + fi + done + if [ "${sorted_blocks}" = "" ]; then + sorted_blocks="${max}" + else + sorted_blocks="${max} ${sorted_blocks}" + fi + blocks="$(__remove_item_in_list "${max}" "${blocks}")" + i=$((i+1)) + done + + echo "${sorted_blocks}" +} + +__unpack_block_item() { + local line="$1" + echo "${line}" | tr '|' ' ' +} + +__pack_block_item() { + local block_name="$1" + local block_pkgs_str="$2" + echo "${block_name}|${block_pkgs_str}" +} + +__unpack_block_pkgs() { + local block_pkgs_str="$1" + echo "${block_pkgs_str}" | tr ',' ' ' +} + +__pack_block_pkgs() { + echo "$*" | tr ' ' ',' +} + +check_install_path() { + local install_path="$1" + + if [ "${install_path}" = "" ]; then + log "ERROR" "install_path is empty!" + return 1 + fi +} + +# 添加pkg对应的block_info +add_pkg_blocks_info() { + local install_path="$1" + local pkg="$2" + shift; shift + # blocks为待加入db.info的块列表 + local blocks="$*" + local block_idx_value + + local db_filepath="${install_path}/${PKG_DB_INFO_RELPATH}" + local db_dirpath="$(dirname "${db_filepath}")" + + local db_filepath_new="${install_path}/${PKG_DB_INFO_RELPATH}~" + + local block_list + local block_name + local block_pkgs_str + local block_pkgs + local len_block_pkgs + local block_idx=0 + local len_blocks + + __length_list "${blocks}" "len_blocks" + if [ ${len_blocks} -eq 0 ]; then + return 0 + fi + + blocks="$(__sort_blocks "${blocks}")" + + if [ ! -d "${db_dirpath}" ]; then + mkdir -p "${db_dirpath}" + if [ $? -ne 0 ]; then + log "ERROR" "mkdir ${db_dirpath} failed!" + exit 1 + fi + fi + + if [ ! -f "${db_filepath}" ]; then + touch "${db_filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "touch ${db_filepath} failed!" + exit 1 + fi + change_mod_and_own "${db_filepath}" "${DB_INFO_MOD}" "\$username:\$usergroup" "${INSTALL_FOR_ALL}" + fi + + rm -f "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${db_filepath_new} failed!" + exit 1 + fi + + while read line; do + block_list="$(__unpack_block_item "${line}")" + __index_list "${block_list}" 0 "block_name" + __index_list "${block_list}" 1 "block_pkgs_str" + + # 如果pkgs为空,则忽略该条目 + if [ "${block_pkgs_str}" = "" ]; then + continue + fi + + block_pkgs="$(__unpack_block_pkgs "${block_pkgs_str}")" + __length_list "${block_pkgs}" "len_block_pkgs" + if [ ${len_block_pkgs} -eq 0 ]; then + continue + fi + + if [ ${block_idx} -lt ${len_blocks} ]; then + __index_list "${blocks}" ${block_idx} "block_idx_value" + fi + + # blocks中的块名小于db中的当前块名,直接添加到db中。 + # 注意不能continue,因为还要处理db的当前条目。 + while [ ${block_idx} -lt ${len_blocks} ] && [ "${block_idx_value}" \< "${block_name}" ]; do + __pack_block_item "${block_idx_value}" "${pkg}" >> "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "write ${db_filepath_new} failed!" + exit 1 + fi + block_idx=$((block_idx+1)) + __index_list "${blocks}" ${block_idx} "block_idx_value" + done + + # 已经没有需要添加的块,保持db的当前条目。 + if [ ${block_idx} -eq ${len_blocks} ]; then + __pack_block_item "${block_name}" "${block_pkgs_str}" >> "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "write ${db_filepath_new} failed!" + exit 1 + fi + continue + fi + + # blocks中的块名大于db中的当前块名,保持db的当前条目。 + if [ "${block_idx_value}" \> "${block_name}" ]; then + __pack_block_item "${block_name}" "${block_pkgs_str}" >> "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "write ${db_filepath_new} failed!" + exit 1 + fi + continue + fi + + # blocks中的块名等于db中的当前块名,将pkg添加到当前条目pkg列表中。 + in_pkgs="$(__pkg_in_pkgs "${pkg}" "${block_pkgs}")" + if [ "${in_pkgs}" = "true" ]; then + __pack_block_item "${block_name}" "${block_pkgs_str}" >> "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "write ${db_filepath_new} failed!" + exit 1 + fi + else + __pack_block_item "${block_name}" "${block_pkgs_str},${pkg}" >> "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "write ${db_filepath_new} failed!" + exit 1 + fi + fi + block_idx=$((block_idx+1)) + done < "${db_filepath}" + + # blocks中剩余的块添加到db中。 + while [ ${block_idx} -lt ${len_blocks} ]; do + __index_list "${blocks}" ${block_idx} "block_idx_value" + echo "${block_idx_value}|${pkg}" >> "${db_filepath_new}" + block_idx=$((block_idx+1)) + done + + cp "${db_filepath_new}" "${db_filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "replace ${db_filepath} failed!" + exit 1 + fi + + rm -f "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${db_filepath_new} failed!" + exit 1 + fi +} + +# 删除block_info中的pkg信息 +del_blocks_info_pkg() { + local install_path="$1" + local pkg="$2" + + local db_filepath="${install_path}/${PKG_DB_INFO_RELPATH}" + local db_dirpath="$(dirname "${db_filepath}")" + + local db_filepath_new="${install_path}/${PKG_DB_INFO_RELPATH}~" + + local block_list + local block_name + local block_pkgs_str + local block_pkgs + local len_block_pkgs + + if [ ! -f "${db_filepath}" ]; then + return 0 + fi + + rm -f "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${db_filepath_new} failed!" + exit 1 + fi + + while read line; do + block_list="$(__unpack_block_item "${line}")" + + __index_list "${block_list}" 0 "block_name" + __index_list "${block_list}" 1 "block_pkgs_str" + + block_pkgs="$(__unpack_block_pkgs "${block_pkgs_str}")" + + block_pkgs="$(__remove_pkg_in_pkgs "${pkg}" "${block_pkgs}")" + + __length_list "${block_pkgs}" "len_block_pkgs" + + if [ ${len_block_pkgs} -gt 0 ]; then + block_pkgs_str="$(__pack_block_pkgs "${block_pkgs}")" + __pack_block_item "${block_name}" "${block_pkgs_str}" >> "${db_filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "write ${db_filepath_new} failed!" + exit 1 + fi + fi + done < "${db_filepath}" + + # 当前条目如果没有pkg使用,则删除。 + if [ ! -f "${db_filepath_new}" ]; then + rm -f "${db_filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${db_filepath} failed!" + exit 1 + fi + else + mv -f "${db_filepath_new}" "${db_filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "replace ${db_filepath} failed!" + exit 1 + fi + fi + return 0 +} + +# 准备并且检查软链接路径 +prepare_and_check_softlink_path() { + local softlink_abs="$1" + local softlink_dir="$(dirname "${softlink_abs}")" + + if [ ! -d "${softlink_dir}" ]; then + mkdir -p "${softlink_dir}" + fi + + # 如果目标路径是个软链接,则移除 + if [ -L "${softlink_abs}" ]; then + rm -f "${softlink_abs}" + if [ $? -ne 0 ]; then + log "ERROR" "remove softlink ${softlink_abs} failed! (create relative softlink)" + exit 1 + fi + fi + + # 不允许目标路径已经是一个目录,防止软链接到错误的位置。 + if [ -d "${softlink_abs}" ]; then + log "ERROR" "softlink existed dir ${softlink_abs}!" + exit 1 + fi +} + +get_file_owner_group() { + local _outvar="$1" + local _path="$2" + local _result + + _result="$(stat -c %U "${_path}"):$(stat -c %G "${_path}")" + eval "${_outvar}=\"${_result}\"" +} + +# 根据pkg_inner_softlink创建软链接 +create_pkg_inner_softlink() { + local install_path="$1" + local line="$2" + local array + local target + local pkg_inner_softlink + local pkg_inner_softlink_list + local is_abs_path + + __index_list "${line}" 1 "target" 8 "pkg_inner_softlink" + + if [ "${pkg_inner_softlink}" != "NA" ]; then + create_softlink_by_install_path "${install_path}" "${target}" "${pkg_inner_softlink}" + fi + return 0 +} + +# 处理软链路径为已存在目录的情况 +# minirc场景,install_path目录下,存在include目录 +# 并且filelist.csv中配置了(x86_64|aarch64)-linux/include目录 +# 则将(x86_64|aarch64)-linux/include中的内容,软链接至include目录下 +deal_with_existed_dir() { + local install_path="$1" + local folder="$2" + local filelist_path="$3" + local install_path_regex="^(x86_64|aarch64)-linux/${folder}$" + local install_sub_path_regex="^(x86_64|aarch64)-linux/${folder}/[^/]+$" + + if [ -L "${install_path}/${folder}" ] || [ ! -d "${install_path}/${folder}" ]; then + return 0 + fi + + target_path=$(awk -v folder="${folder}" -v install_path_regex="${install_path_regex}" ' + BEGIN{ + FS= "," + } + { + if ($2 != "mkdir") next + + if ($4 !~ install_path_regex) next + + if ($9 != folder) next + + print $4 + }' "${filelist_path}") + + if [ "${target_path}" = "" ]; then + return 0 + fi + + awk -v folder="${folder}" -v install_path_regex="${install_path_regex}" -v install_sub_path_regex="${install_sub_path_regex}" ' + BEGIN{ + FS = ","; OFS = "," + } + { + if ($2 != "mkdir" && $2 != "copy" && $2 != "move") { + print $0 + next + } + if ($4 ~ install_path_regex) { + print $1, $2, $3, $4, $5, $6, $7, $8, "NA", $10, $11, $12, $13, $14, $15 + next + } + if ($4 !~ install_sub_path_regex) { + print $0 + next + } + softlink = $9 + if (softlink != "NA") { + print $0 + next + } + + z = split($4, filepath_list, "/") + softlink = folder "/" filepath_list[z] + print $1, $2, $3, $4, $5, $6, $7, $8, softlink, $10, $11, $12, $13, $14, $15 + }' "${filelist_path}" > "${filelist_path}.tmp" + if [ $? -ne 0 ]; then + log "ERROR" "modify filelist for ${install_path}/${folder} failed!" + return 1 + fi + + mv -f "${filelist_path}.tmp" "${filelist_path}" + if [ $? -ne 0 ]; then + log "ERROR" "replace filelist for ${install_path}/${folder} failed!" + return 1 + fi +} + +#执行创建目录动作 +do_create_dirs() { + local action="$1" + local install_type="$2" + local install_path="$3" + local filelist_path="$4" + local package="$5" + local feature_param="$6" + local ret + + if [ "${action}" = "resetmod" ]; then + if [ "${package}" != "" ]; then + del_blocks_info_pkg "${install_path}" "${package}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + create_stash_mod "${install_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "NA" "reset_mod_dirs_with_stash_mod" "${install_type}" "${install_path}" "mkdir" "${filelist_path}" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + else + foreach_filelist "NA" "reset_mod_dirs" "${install_type}" "${install_path}" "mkdir" "${filelist_path}" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + # 设置copy_entity路径的权限,解决删除时权限问题 + # filter_by_blocks过滤,防止变更不删除的文件(目录)的权限 + foreach_filelist "filter_by_blocks" "reset_mod_dirs_recursive" "${install_type}" "${install_path}" "copy_entity" "${filelist_path}" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + elif [ "${action}" = "all" ] || [ "${action}" = "mkdir" ]; then + deal_with_existed_dir "$install_path" "include" "$filelist_path" + ret="$?" && [ $ret -ne 0 ] && return $ret + + deal_with_existed_dir "$install_path" "lib64" "$filelist_path" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 先重置目录权限配置,防止软链接时缺少权限 + foreach_filelist "NA" "reset_mod_dirs" "$install_type" "$install_path" "mkdir" "$filelist_path" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 重置copy_entity权限,防止块复用场景,复制时缺少权限 + foreach_filelist "NA" "reset_mod_dirs_recursive" "$install_type" "$install_path" "copy_entity" "$filelist_path" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "NA" "create_dirs" "$install_type" "$install_path" "mkdir" "$filelist_path" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "filter_by_pkg_inner_softlink" "create_pkg_inner_softlink" "$install_type" "$install_path" "mkdir" "$filelist_path" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + else + log "ERROR" "action wrong! action is ${action}" + return 1 + fi + + return 0 +} + +# 拷贝文件 +copy_file() { + local install_path="$1" + local source="$2" + local target="$3" + local softlink="$4" + local pkg_inner_softlink="$5" + local target_abs + local target_dir + + __set_abs_path "${install_path}" "${target}" "target_abs" + target_dir="$(dirname "${target_abs}")" + + if [ ! -e "${source}" ]; then + log "ERROR" "copy file source file ${source} doesn't exist!" + return 1 + fi + + ${COPY_COMMAND} "${source}" "${target_dir}" + if [ $? -ne 0 ]; then + log "ERROR" "${source} copy failed!" + return 1 + fi + if [ "${softlink}" != "NA" ]; then + create_softlink_by_install_path "${install_path}" "${target}" "${softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + if [ "${pkg_inner_softlink}" != "NA" ]; then + create_softlink_by_install_path "${install_path}" "${target}" "${pkg_inner_softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + return 0 +} + +# 移动文件 +move_file() { + local install_path="$1" + local source="$2" + local target="$3" + local softlink="$4" + local pkg_inner_softlink="$5" + local target_abs + local target_dir + + __set_abs_path "${install_path}" "${target}" "target_abs" + target_dir="$(dirname "${target_abs}")" + + if [ ! -e "${source}" ] && [ ! -L "${source}" ]; then + log "ERROR" "move file source file ${source} doesn't exist!" + return 1 + fi + + ${MOVE_COMMAND} "${source}" "${target_dir}" + if [ $? -ne 0 ]; then + log "ERROR" "${source} move failed!" + return 1 + fi + if [ "${softlink}" != "NA" ]; then + create_softlink_by_install_path "${install_path}" "${target}" "${softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + if [ "${pkg_inner_softlink}" != "NA" ]; then + create_softlink_by_install_path "${install_path}" "${target}" "${pkg_inner_softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + return 0 +} + +# 复制文件 +copy_files() { + local install_path="$1" + local line="$2" + local exec_params="$3" + local src_dir="$4" + local src src_abs target target_abs softlink configurable pkg_inner_softlink tmpdir action + local ret + + __index_list "${line}" 0 "src" 1 "target" 4 "softlink" 5 "configurable" 8 "pkg_inner_softlink" + if [ "${src_dir}" = "--move" ]; then + src_abs="${src}" + action="move_file" + elif [ "${src_dir}" != "" ]; then + __set_abs_path "${src_dir}" "${src}" "src_abs" + action="copy_file" + else + src_abs="${src}" + action="copy_file" + fi + __set_abs_path "${install_path}" "${target}" "target_abs" + + tmpdir="$(dirname "${target_abs}")" + if [ ! -d "${tmpdir}" ]; then + mkdir -p "${tmpdir}" + fi + + # 如果目标文件已经存在,而且是配置文件,则不执行覆盖操作 + if [ -e "${target_abs}" ] && [ "${configurable}" = "TRUE" ]; then + return 0 + fi + + # 源文件不是软链,并且目标文件是软链 + if [ ! -L "${src_abs}" ] && [ -L "${target_abs}" ] ; then + rm -f "${target_abs}" + log "WARNING" "${target_abs} is an existing softlink in copy files, deleted." + fi + + exec_with_param "$exec_params" "$action" "${install_path}" "${src_abs}" "${target}" "${softlink}" "${pkg_inner_softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + return 0 +} + +__set_total_uninstall_path() { + local install_path="$1" + local varname="$2" + + eval "${varname}=\"${install_path}/cann_uninstall.sh\"" +} + +# 是否为hilinux环境 +__is_hilinux() { + local varname="$1" + + which lsattr > /dev/null 2>&1 + if [ $? -ne 0 ]; then + eval "${varname}=\"true\"" + else + eval "${varname}=\"false\"" + fi +} + +# 移除文件上的不可修改权限 +__remove_immutable() { + local file="$1" + local is_hilinux ret + + # 文件不存在则退出。 + if [ ! -f "${file}" ]; then + return 0 + fi + + __is_hilinux "is_hilinux" + if [ "${is_hilinux}" = "true" ]; then + return 0 + fi + + attr="$(lsattr "${file}" | cut -d' ' -f1 | grep -o "i")" + if [ "${attr}" != "" ]; then + chattr -i "${file}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + return 0 +} + +# 创建总uninstall.sh脚本 +__create_uninstall() { + local file="$1" + + if [ ! -f "${file}" ]; then + cat > ${file} < /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "WARNING" "Delete file:${file} failed, please delete it by yourself." + fi + fi + return 0 +} + +# 向cann_uninstall.sh文件中添加uninstall_package命令 +add_cann_uninstall_script_dir() { + local install_path="$1" + local script_dir="$2" + local username="$3" + local usergroup="$4" + local install_for_all="$5" + local oldmod="" ret + + __set_total_uninstall_path "${install_path}" "total_uninstall_path" + + if [ -f "${install_path}/${script_dir}/uninstall.sh" ]; then + if [ -f "${total_uninstall_path}" ]; then + get_file_mod "oldmod" "${total_uninstall_path}" + else + __create_uninstall "${total_uninstall_path}" + fi + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_immutable "${total_uninstall_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_own "${total_uninstall_path}" "${username}:${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_mod "${total_uninstall_path}" "${SETENV_WRITEABLE_MOD}" "" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __add_uninstall_package "${total_uninstall_path}" "${script_dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${oldmod}" = "" ]; then + change_mod "${total_uninstall_path}" "${TOTAL_UNINSTALL_MOD}" "${install_for_all}" + else + change_mod "${total_uninstall_path}" "${oldmod}" "" + fi + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# 向cann_uninstall.sh文件中添加子包命令 +add_cann_uninstall_package() { + local install_path="$1" + local package="$2" + local username="$3" + local usergroup="$4" + local install_for_all="$5" + local ret package_dirpath script_dir + + get_package_dirpath "package_dirpath" "${package}" + script_dir="${package_dirpath}/script" + + # graph_autofusion_kernel包存在同时安装多种芯片包的场景 + # 确保cann_uninstall.sh脚本中只有一个graph_autofusion_kernel的uninstall_package + del_cann_uninstall_script_dir "${install_path}" "${script_dir}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + add_cann_uninstall_script_dir "${install_path}" "${script_dir}" "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# cann_uninstall.sh文件中添加命令(命令入口) +do_add_cann_uninstall() { + local install_path="$1" + local script_dir="$2" + local username="$3" + local usergroup="$4" + local install_for_all="$5" + local ret + + check_param_not_empty "install_path" "need set package parameter in add cann uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + check_param_not_empty "script_dir" "need set script_dir parameter in add cann uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + check_param_not_empty "username" "need set username parameter in add cann uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + check_param_not_empty "usergroup" "need set usergroup parameter in add cann uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 删除cann_uninstall.sh文件中已存在的uninstall_package命令 + del_cann_uninstall_script_dir "${install_path}" "${script_dir}" + add_cann_uninstall_script_dir "${install_path}" "${script_dir}" "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 删除cann_uninstall.sh文件中uninstall_package命令 +del_cann_uninstall_script_dir() { + local install_path="$1" + local script_dir="$2" + local oldmod="" ret + + __set_total_uninstall_path "${install_path}" "total_uninstall_path" + + if [ -f "${total_uninstall_path}" ]; then + __remove_immutable "${total_uninstall_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_file_mod "oldmod" "${total_uninstall_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_mod "${total_uninstall_path}" "${SETENV_WRITEABLE_MOD}" "" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_uninstall_package "${total_uninstall_path}" "${script_dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_mod "${total_uninstall_path}" "${oldmod}" "" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_uninstall_file_if_no_content "${total_uninstall_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + return 0 +} + +# 删除cann_uninstall.sh文件中子包命令 +del_cann_uninstall_package() { + local install_path="$1" + local package="$2" + local ret package_dirpath script_dir + + get_package_dirpath "package_dirpath" "${package}" + script_dir="${package_dirpath}/script" + + del_cann_uninstall_script_dir "${install_path}" "${script_dir}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# cann_uninstall.sh文件中删除命令(命令入口) +do_del_cann_uninstall() { + local install_path="$1" + local script_dir="$2" + local ret + + check_param_not_empty "install_path" "need set package parameter in del cann uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + check_param_not_empty "script_dir" "need set script_dir parameter in del cann uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + del_cann_uninstall_script_dir "${install_path}" "${script_dir}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 删除ascend_install.info文件 +del_ascend_install_info() { + local install_path="$1" + local package="$2" + local package_dirpath + + get_package_dirpath "package_dirpath" "$package" + rm -f "$install_path/$package_dirpath/ascend_install.info" +} + +# 执行拷贝动作 +do_copy_files() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local package="$4" + local feature_param="$5" + local total_uninstall_path exec_mode ret + + if [ "$PARALLEL" = "true" ]; then + exec_mode="concurrency" + else + exec_mode="normal" + fi + if [ "${USE_MOVE}" = "true" ]; then + foreach_filelist "NA" "copy_files" "$install_type" "$install_path" "move" "$filelist_path" "${feature_param}" \ + "no" "$exec_mode" "--move" + foreach_filelist "NA" "copy_files" "$install_type" "$install_path" "copy copy_entity" "$filelist_path" "${feature_param}" \ + "no" "$exec_mode" + else + foreach_filelist "NA" "copy_files" "$install_type" "$install_path" "copy copy_entity move" "$filelist_path" "${feature_param}" \ + "no" "$exec_mode" + fi + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${package}" != "" ] && [ "${SET_CANN_UNINSTALL}" = "y" ]; then + add_cann_uninstall_package "${install_path}" "${package}" "${USERNAME}" "${USERGROUP}" "${INSTALL_FOR_ALL}" + fi +} + +# 修改文件的权限和属组 +change_mod_and_own_files() { + local install_path="$1" + local line="$2" + local exec_params="$3" + local target mod own is_abs_path + + __index_list "${line}" 1 "target" 2 "mod" 3 "own" + __check_abs_path "${target}" + if [ "${is_abs_path}" != "true" ]; then + target="${install_path}/${target}" + fi + if [ -d "${target}" ]; then + return 0 + fi + # 只处理文件,没有处理文件的软链接 + exec_with_param "$exec_params" change_mod_and_own "${target}" "${mod}" "${own}" "${INSTALL_FOR_ALL}" "false" +} + +# 递归修改文件的权限和属组 +change_mod_and_own_files_recursive() { + local install_path="$1" + local line="$2" + local exec_params="$3" + local target mod own is_abs_path + + __index_list "${line}" 1 "target" 2 "mod" 3 "own" + __check_abs_path "${target}" + if [ "${is_abs_path}" != "true" ]; then + target="${install_path}/${target}" + fi + if [ ! -e "${target}" ]; then + return 0 + fi + + exec_with_param "$exec_params" change_mod_and_own "${target}" "${mod}" "${own}" "${INSTALL_FOR_ALL}" "true" +} + +# filelist中的使用到的blocks,添加到db.info中 +add_filelist_blocks_info() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local feature_param="$4" + local package="$5" + local blocks="" + + parse_filelist "${install_type}" "copy copy_entity del mkdir move" "${filelist_path}" "${feature_param}" "NA" "" + filelist="$(echo "${filelist}" | cut -d' ' -f8 | sort | uniq)" + + while read line; do + block_name="${line}" + if [ "${block_name}" = "" ]; then + continue + fi + if [ "${blocks}" = "" ]; then + blocks="${block_name}" + else + blocks="${blocks} ${block_name}" + fi + done << EOF +${filelist} +EOF + add_pkg_blocks_info "${install_path}" "${package}" "${blocks}" +} + +# 修改文件和目录的权限 +do_chmod_file_dir() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local feature_param="$4" + local package="$5" + local ret + + foreach_filelist "NA" "change_mod_and_own_files" "$install_type" "$install_path" "copy del move" "$filelist_path" "${feature_param}" "no" "concurrency" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "NA" "change_mod_and_own_files_recursive" "$install_type" "$install_path" "copy_entity" "$filelist_path" "${feature_param}" "no" "concurrency" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "NA" "change_mod_and_own_dirs" "$install_type" "$install_path" "mkdir" "$filelist_path" "${feature_param}" "reverse" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${package}" != "" ]; then + add_filelist_blocks_info "$install_type" "$install_path" "$filelist_path" "${feature_param}" "$package" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# 删除安装生成的pkg_inner_softlinks +remove_install_pkg_inner_softlinks() { + local install_path="$1" + local line="$2" + local target + local pkg_inner_softlink + local pkg_inner_softlink_list + local pkg_inner_softlink_abs + local ret + + __index_list "${line}" 1 "target" 8 "pkg_inner_softlink" + if [ "${target}" != "NA" ]; then + if [ "${pkg_inner_softlink}" != "NA" ]; then + remove_softlinks "${install_path}" "${pkg_inner_softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + fi + return 0 +} + +# 删除安装文件,入参为$1: install_type, $2: install_path $3:filelist_path +remove_install_files() { + local install_path="$1" + local line="$2" + local exec_params="$3" + local target softlink configurable hash_value is_abs_path + + __index_list "${line}" 1 "target" 4 "softlink" 5 "configurable" 6 "hash_value" + + if [ "${target}" != "NA" ]; then + __check_abs_path "${target}" + if [ "${is_abs_path}" != "true" ]; then + target="${install_path}/${target}" + fi + if [ -d "${target}" ] && [ ! -L "${target}" ]; then + return 0 + fi + if [ "${softlink}" != "NA" ]; then + __check_abs_path "${softlink}" + if [ "${is_abs_path}" != "true" ]; then + softlink="${install_path}/${softlink}" + fi + fi + # 配置文件不删除 + if [ "${configurable}" = "TRUE" ]; then + echo "${hash_value} ${target}" | sha256sum --check > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "WARNING" "${target} user configuration file has been modified, skip deleting." + return 0 + fi + fi + exec_with_param "$exec_params" remove_file "${target}" "${softlink}" + fi + return 0 +} + +# 递归删除安装文件 +remove_install_files_recursive() { + local install_path="$1" + local line="$2" + local exec_params="$3" + local target configurable hash_value is_abs_path + + __index_list "${line}" 1 "target" 5 "configurable" 6 "hash_value" + + if [ "${target}" != "NA" ]; then + __check_abs_path "${target}" + if [ "${is_abs_path}" != "true" ]; then + target="${install_path}/${target}" + fi + # 配置文件不删除 + if [ "${configurable}" = "TRUE" ]; then + echo "${hash_value} ${target}" | sha256sum --check > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "WARNING" "${target} user configuration file has been modified, skip deleting." + return 0 + fi + fi + exec_with_param "$exec_params" remove_dir_icp "${target}" + fi + return 0 +} + +# 删除安装文件夹生成的软链接 +remove_install_softlink() { + local install_path="$1" + local line="$2" + local target + local softlinks_str + local is_abs_path + + __index_list "${line}" 1 "target" 4 "softlinks_str" + + if [ "$target" != "NA" ]; then + if [ "${softlinks_str}" != "NA" ]; then + remove_softlinks "${install_path}" "${softlinks_str}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + fi + return 0 +} + +# 删除安装文件与目录等 +do_remove() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local package="$4" + local feature_param="$5" + local tmp_filelist_path + local total_uninstall_path + local oldmod + local func_before_remove + local func_after_remove_01 + local func_after_remove_02 + local ret + + get_tmp_file tmp_filelist_path "filelist" + cp -f "$filelist_path" "$tmp_filelist_path" + + if [ $? -ne 0 ]; then + log "ERROR" "cp -f $filelist_path $tmp_filelist_path failed!" + return 1 + fi + + if [ "${package}" != "" ]; then + # root帐户--uninstall时,存在不调用restoremod,直接调用remove的场景。(toolkit包) + func_before_remove="del_blocks_info_pkg \"${install_path}\" \"${package}\"" + if [ -f "${install_path}/${STASH_MOD_PATH}" ]; then + # 删除文件后,恢复目录权限配置 + func_after_remove_01="foreach_stashmod \"restore_stash_mod\" \"${install_path}\" \"reverse\"" + func_after_remove_02="remove_stash_mod \"${install_path}\"" + fi + + del_cann_uninstall_package "${install_path}" "${package}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "$REMOVE_INSTALL_INFO" = "y" ]; then + del_ascend_install_info "$install_path" "$package" + fi + fi + + eval "${func_before_remove}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # del元素不会出现pkg_inner_softlink + foreach_filelist "filter_by_pkg_inner_softlink" "remove_install_pkg_inner_softlinks" "$install_type" "$install_path" "mkdir copy copy_entity move" "$tmp_filelist_path" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "filter_by_blocks" "remove_install_softlink" "$install_type" "$install_path" "mkdir copy copy_entity move" "$tmp_filelist_path" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "filter_by_blocks" "remove_install_files" "$install_type" "$install_path" "copy del move" "$tmp_filelist_path" "${feature_param}" "no" "concurrency" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "filter_by_blocks" "remove_install_files_recursive" "$install_type" "$install_path" "copy_entity" "$tmp_filelist_path" "${feature_param}" "no" "concurrency" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "filter_by_blocks" "remove_install_dirs" "$install_type" "$install_path" "mkdir" "$tmp_filelist_path" "${feature_param}" "reverse" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + eval "${func_after_remove_01}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + eval "${func_after_remove_02}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + rm -f "$tmp_filelist_path" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 打印安装信息 +print_install_content() { + local install_type="$1" + local install_path="$2" + local operate_type="$3" + local filelist_path="$4" + local feature_param="$5" + local blocks + + get_blocks_info "blocks" "$install_path" + parse_filelist "$install_type" "$operate_type" "$filelist_path" "$feature_param" "filter_by_blocks" "$blocks" + + # bash与dash的echo有差异,需要使用系统的/bin/echo + /bin/echo "$filelist" + exit 0 +} + +# 包名是否存在于db.info +pkg_in_dbinfo() { + local install_path="$1" + local pkg="$2" + + local db_filepath="${install_path}/${PKG_DB_INFO_RELPATH}" + + if [ -z "${install_path}" ]; then + echo "false" + exit 1 + fi + + if [ -z "${pkg}" ]; then + echo "false" + exit 2 + fi + + if [ ! -f "${db_filepath}" ]; then + echo "false" + return 0 + fi + + awk -v input_pkg="${pkg}" ' + BEGIN { + FS = "|" + found = "false" + } + { + split($2, pkg_list, ",") + + for (i in pkg_list) { + if (input_pkg == pkg_list[i]) { + found = "true" + exit + } + } + } + END { + print found + }' "${db_filepath}" +} + +# 展开自定义选项 +expand_custom_options() { + local _outvar="$1" + local _custom_options="$2" + + eval "${_outvar}=\"$(echo "${_custom_options}" | tr "," " ")\"" +} + +# 调用子包自定义脚本 +package_custom_script() { + local script_name="$1" + local install_path="$2" + local version_dir="$3" + local custom_options="$4" + local ret install_options="" + + if [ ! -f "${curpath}/${script_name}" ]; then + return 0 + fi + + install_options="--install-path=${install_path}" + + if [ "${version_dir}" != "" ]; then + install_options="${install_options} --version-dir=${version_dir}" + fi + + expand_custom_options "custom_options" "${custom_options}" + + chmod u+x ${curpath}/${script_name} + ${curpath}/${script_name} ${install_options} ${custom_options} + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 调用子包自定义安装脚本 +package_custom_install() { + local package="$1" + local install_path="$2" + local version_dir="$3" + local custom_options="$4" + local ret + + package_custom_script "${package}_custom_install.sh" "${install_path}" "${version_dir}" "${custom_options}" + check_ret_error "$?" "Run ${package} custom install failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 调用子包自定义卸载脚本 +package_custom_uninstall() { + local package="$1" + local install_path="$2" + local version_dir="$3" + local custom_options="$4" + local ret + + package_custom_script "${package}_custom_uninstall.sh" "${install_path}" "${version_dir}" "${custom_options}" + check_ret_error "$?" "Run ${package} custom uninstall failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 版本安装流程函数 +version_install() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local package="$4" + local feature_param="$5" + local version_dir="$6" + local username="$7" + local usergroup="$8" + local setenv="$9" + local is_upgrade="${10}" + local docker_root="${11}" + local custom_options="${12}" + local is_simple="${13}" + local install_path_full="" ret + local package_real + + if [ "${version_dir}" != "" ]; then + install_path_full="${install_path}/${version_dir}" + else + install_path_full="${install_path}" + fi + + if [ "${is_simple}" = "y" ]; then + package_real="" + else + package_real="${package}" + fi + + # 创建目录 + do_create_dirs "mkdir" "${install_type}" "${install_path_full}" "${filelist_path}" "${package_real}" "${feature_param}" + if [ $? -ne 0 ]; then + log "ERROR" "failed to create folder." + return 1 + fi + + # 拷贝目录与文件 + do_copy_files "${install_type}" "${install_path_full}" "${filelist_path}" "${package_real}" "${feature_param}" + if [ $? -ne 0 ]; then + log "ERROR" "failed to copy files." + return 1 + fi + + if [ "${is_simple}" != "y" ]; then + # set env + add_setenv "${install_path_full}" "${package_real}" "${setenv}" "${username}" "${usergroup}" "false" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # set prereq_check + add_prereq_check "${install_path_full}" "${package_real}" "${username}" "${usergroup}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 调用组件自定义安装流程 + package_custom_install "${package_real}" "${install_path}" "${version_dir}" "${custom_options}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + # 文件与目录赋权 + do_chmod_file_dir "${install_type}" "${install_path_full}" "${filelist_path}" "${feature_param}" "${package_real}" + if [ $? -ne 0 ]; then + log "ERROR" "failed to chown files." + return 1 + fi + + return 0 +} + +# 版本卸载流程函数 +version_uninstall() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local package="$4" + local feature_param="$5" + local version_dir="$6" + local username="$7" + local docker_root="$8" + local custom_options="$9" + local is_simple="${10}" + local install_path_full="" ret total_ret=0 + local package_real + + if [ "${version_dir}" != "" ]; then + install_path_full="${install_path}/${version_dir}" + else + install_path_full="${install_path}" + fi + + if [ "${is_simple}" = "y" ]; then + package_real="" + else + package_real="${package}" + fi + + # 恢复权限 + do_create_dirs "resetmod" "${install_type}" "${install_path_full}" "${filelist_path}" "${package_real}" "${feature_param}" + if [ $? -ne 0 ]; then + log "ERROR" "failed to resetmod chmod." + return 1 + fi + + if [ "${is_simple}" != "y" ]; then + # unset env + del_setenv "${install_path_full}" "${package_real}" "${username}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # unset prereq_check + del_prereq_check "${install_path_full}" "${package_real}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 调用组件自定义卸载流程,失败流程不中断 + package_custom_uninstall "${package_real}" "${install_path}" "${version_dir}" "${custom_options}" + ret="$?" && [ $ret -ne 0 ] && total_ret="$ret" + fi + + # 删除文件和目录 + do_remove "${install_type}" "${install_path_full}" "${filelist_path}" "${package_real}" "${feature_param}" + if [ $? -ne 0 ]; then + log "ERROR" "failed to remove files and dirs." + return 1 + fi + + return ${total_ret} +} + +# 版本安装函数 +do_install() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local package="$4" + local feature_param="$5" + local docker_root="$6" + local is_simple="$7" + local install_path_real ret + + check_param_not_empty "package" "need set package parameter in install!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + _package_to_log_pkg_name "LOG_PKG_NAME" "${package}" + check_ret_error "$?" "Set log package name failed in install!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + expand_version_file + + # 获取filelist.csv文件真实路径 + get_realpath "filelist_path" "${filelist_path}" + # 获取install_path真实路径 + get_realpath "install_path" "${install_path}" + + if [ "${docker_root}" != "" ]; then + if [ "${WITH_DOCKER_ROOT_PREFIX}" = "y" ]; then + install_path_real="${install_path}" + else + install_path_real="${docker_root}${install_path}" + fi + else + install_path_real="${install_path}" + fi + + if [ "${VERSION}" != "" ] && [ "${VERSION_DIR}" != "" ]; then + multi_version_install "${install_type}" "${install_path_real}" "${filelist_path}" "${package}" "${feature_param}" \ + "${VERSION}" "${VERSION_DIR}" "${USERNAME}" "${USERGROUP}" "${SETENV}" "${IS_UPGRADE}" "${docker_root}" "${CUSTOM_OPTIONS}" \ + "${INSTALL_FOR_ALL}" + ret="$?" && [ $ret -ne 0 ] && return $ret + else + version_install "${install_type}" "${install_path_real}" "${filelist_path}" "${package}" "${feature_param}" \ + "" "${USERNAME}" "${USERGROUP}" "${SETENV}" "${IS_UPGRADE}" "${docker_root}" "${CUSTOM_OPTIONS}" "${is_simple}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + return 0 +} + +# 版本卸载函数 +do_uninstall() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local package="$4" + local feature_param="$5" + local docker_root="$6" + local is_simple="$7" + local install_path_real ret + + check_param_not_empty "package" "need set package parameter in uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + _package_to_log_pkg_name "LOG_PKG_NAME" "${package}" + check_ret_error "$?" "Set log package name failed in uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + expand_version_file + + # 获取filelist.csv文件真实路径 + get_realpath "filelist_path" "${filelist_path}" + # 获取install_path真实路径 + get_realpath "install_path" "${install_path}" + + if [ "${docker_root}" != "" ]; then + if [ "${WITH_DOCKER_ROOT_PREFIX}" = "y" ]; then + install_path_real="${install_path}" + else + install_path_real="${docker_root}${install_path}" + fi + else + install_path_real="${install_path}" + fi + + if [ "${VERSION}" != "" ] && [ "${VERSION_DIR}" != "" ]; then + multi_version_uninstall "${install_type}" "${install_path_real}" "${filelist_path}" "${package}" "${feature_param}" \ + "${VERSION}" "${VERSION_DIR}" "${USERNAME}" "${USERGROUP}" "${docker_root}" "${CUSTOM_OPTIONS}" "${IS_RECREATE_SOFTLINK}" + ret="$?" && [ $ret -ne 0 ] && return $ret + else + version_uninstall "${install_type}" "${install_path_real}" "${filelist_path}" "${package}" "${feature_param}" \ + "" "${USERNAME}" "${docker_root}" "${CUSTOM_OPTIONS}" "${is_simple}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + return 0 +} + +help_info() { + echo "Usage:" + echo "" + echo " ----------------------------------------------------------------------------------------------------" + echo "" + echo " $0 {--install,--uninstall,--mkdir,--makedir,--copy,--chmoddir,--restoremod,--remove}" + echo "" + echo " --install : Install package." + echo " --uninstall : Uninstall package." + echo " --mkdir : (Deprecated) Use --install instead. Create the install directories." + echo " --makedir : (Deprecated) Use --install instead. Create the install directories." + echo " --copy : (Deprecated) Use --install instead. Copy install files." + echo " --chmoddir : (Deprecated) Use --install instead. Set installed file's right." + echo " --restoremod : (Deprecated) Use --uninstall instead. Restore directories right." + echo " --remove : (Deprecated) Use --uninstall instead. Remove installed files." + echo "" + echo " Group options:" + echo " --install-path= : Specify install path." + echo " --username= : Specify install username." + echo " --usergroup= : Specify install usergroup." + echo " --install_for_all : Install for all users." + echo " Usually specified in root user install scene." + echo " --docker-root= : Specify docker root path." + echo " Install path is not contained docker root path." + echo " --chip= : Specify chip." + echo " Install files which chip matched or chip is all." + echo " --feature= : Specify feature. Default is all." + echo " Install files which feature matched or feature is comm." + echo " --feature-exclude-all : Switch feature mode." + echo " Install files which feature matched." + echo "" + echo " $0 --install [options] " + echo "" + echo " Command options:" + echo " --package= : Specify package name." + echo " --version= : Specify version. --version-file is recommended." + echo " --version-dir= : Specify version directory. --version-file is recommended." + echo " --version-file= : Specify version info file path." + echo " Common script will parse version and version_dir from version_file." + echo " If you specified this option, --version and --version-dir options" + echo " no longer need to be specified." + echo " --custom-options= : Specify custom options for package custom script." + echo " --setenv : Add \"source setenv.\${shell_type}\" to rcfile." + echo " --set-cann-uninstall : Add uninstall command into cann_uninstall.sh." + echo " Always specified this in multi-version install." + echo "" + echo " $0 --uninstall [options] " + echo "" + echo " Command options:" + echo " --package= : Specify package name." + echo " --version= : Specify version. --version-file is recommended." + echo " --version-dir= : Specify version directory. --version-file is recommended." + echo " --version-file= : Specify version info file path." + echo " Common script will parse version and version_dir from version_file." + echo " If you specified this option, --version and --version-dir options" + echo " no longer need to be specified." + echo " --custom-options= : Specify custom options for package custom script." + echo "" + echo " ----------------------------------------------------------------------------------------------------" + echo "" + echo " $0 {--add-cann-uninstall,--del-cann-uninstall}" + echo "" + echo " --add-cann-uninstall : Add uninstall command in cann_uninstall.sh." + echo " --del-cann-uninstall : Del uninstall command in cann_uninstall.sh." + echo "" + echo " Group options:" + echo " --install-path= : Specify install path." + echo "" + echo " $0 --add-cann-uninstall [options] " + echo "" + echo " Command options:" + echo " --username= : Specify install username." + echo " --usergroup= : Specify install usergroup." + echo " --install_for_all : Install for all users." + echo " Usually specified in root user install scene." + echo "" + echo " $0 --del-cann-uninstall [options] " + echo "" + echo " ----------------------------------------------------------------------------------------------------" + echo "" + echo " $0 {--add-env-rc,--del-env-rc}" + echo "" + echo " --add-env-rc : Add \"source setenv.\${shell_type}\" to rcfile." + echo " --del-env-rc : Del \"source setenv.\${shell_type}\" in rcfile." + echo "" + echo " Group options:" + echo " --username= : Specify install username." + echo " --usergroup= : Specify install usergroup." + echo " --docker-root= : Specify docker root path." + echo " Install path is not contained docker root path." + echo "" + echo " $0 --add-env-rc [options] " + echo "" + echo " Command options:" + echo " --package= : Specify package name." + echo " --setenv : Add \"source setenv.\${shell_type}\" to rcfile." + echo "" + echo " $0 --del-env-rc [options] " + echo "" + echo " ----------------------------------------------------------------------------------------------------" + echo "" + echo " $0 --pkg-in-dbinfo " + echo "" + echo " Does package in ascend_package_db.info. Echo true or false." + echo "" + echo " Command options:" + echo " --package= : Specify package name." + echo "" + echo " ----------------------------------------------------------------------------------------------------" + echo "" + echo " $0 --help" + echo "" + echo " Print help messages." +} + +# env rc相关命令 +env_rc_commands() { + local install_path + local setenv_filepath + local shell_type + + case "${OPERATE_TYPE}" in + "add-env-rc") + install_path="$1" + setenv_filepath="$2" + shell_type="$3" + add_env_rc "${install_path}" "${setenv_filepath}" "${PACKAGE}" "${shell_type}" "${SETENV}" "${USERNAME}" "${USERGROUP}" "false" "${DOCKER_ROOT}" + exit 0 + ;; + "del-env-rc") + install_path="$1" + setenv_filepath="$2" + shell_type="$3" + del_env_rc "${install_path}" "${setenv_filepath}" "${shell_type}" "${USERNAME}" "${DOCKER_ROOT}" + exit 0 + ;; + esac +} + +# db.info相关命令 +dbinfo_commands() { + local install_path + + case "${OPERATE_TYPE}" in + "pkg-in-dbinfo") + install_path="$1" + pkg_in_dbinfo "${install_path}" "${PACKAGE}" + exit 0 + esac +} + +# spc相关命令 +spc_commands() { + local install_path="$1" + local filelist_path="$2" + local filelist_spc_path="$3" + local version_dir="$4" + local ret + + case "${OPERATE_TYPE}" in + "spc_install") + install_patch "${install_path}" "${filelist_path}" "${filelist_spc_path}" "${version_dir}" + exit $? + ;; + "spc_rollback") + rollback_patch "${install_path}" "${filelist_path}" "${version_dir}" + exit 0 + ;; + "spc_uninstall") + uninstall_patch "${install_path}" "${filelist_path}" "${version_dir}" + exit 0 + ;; + esac +} + +# cann_uninstall总卸载脚本相关命令 +cann_uninstall_commands() { + local script_dir="$1" + local ret + + case "${OPERATE_TYPE}" in + "add-cann-uninstall") + do_add_cann_uninstall "${INSTALL_PATH}" "${script_dir}" "${USERNAME}" "${USERGROUP}" "${INSTALL_FOR_ALL}" + ret="$?" && [ ${ret} -ne 0 ] && exit 1 + exit 0 + ;; + "del-cann-uninstall") + do_del_cann_uninstall "${INSTALL_PATH}" "${script_dir}" + ret="$?" && [ ${ret} -ne 0 ] && exit 1 + exit 0 + ;; + esac +} + +# 多版本创建相关命令 +multi_version_commands() { + case "${OPERATE_TYPE}" in + "notify_create_softlink") + notify_latest_manager_create_softlink "$INSTALL_PATH/$LATEST_DIR/var" "$PACKAGE" "$VERSION" "$VERSION_DIR" \ + "$INSTALL_FOR_ALL" "$DOCKER_ROOT" + ret="$?" && [ $ret -ne 0 ] && exit 1 + exit 0 + ;; + "notify_remove_softlink") + notify_latest_manager_remove_softlink "$INSTALL_PATH/$LATEST_DIR/var" "$PACKAGE" "$VERSION" "$VERSION_DIR" \ + "$INSTALL_FOR_ALL" "$DOCKER_ROOT" + ret="$?" && [ $ret -ne 0 ] && exit 1 + exit 0 + ;; + esac +} + +# 正式命令 +formal_commands() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local input_feature input_chip + local ret docker_root + local feature_param thread_num + + if [ "$FEATURE" != "all" ]; then + normalize_feature "input_feature" "$FEATURE" "${OPERATE_TYPE}" + else + if [ $# = 3 ]; then + input_feature="all" + else + normalize_feature "input_feature" "$4" "${OPERATE_TYPE}" + fi + fi + normalize_feature "input_chip" "$CHIP" "${OPERATE_TYPE}" + + pack_feature_param "feature_param" "${input_feature}" "${FEATURE_EXCLUDE_ALL}" "${input_chip}" + + # 移除docker_root右侧的/ + rstrip_path "docker_root" "${DOCKER_ROOT}" + + if [ "$PARALLEL_LIMIT" = "true" ]; then + get_thread_num "thread_num" + init_fifo "PARALLEL_FIFO" "$thread_num" + fi + + case "${OPERATE_TYPE}" in + "install") + do_install "${install_type}" "${install_path}" "${filelist_path}" "${PACKAGE}" "${feature_param}" "${docker_root}" "n" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "uninstall") + # 统一使用full模式卸载文件。两个包共用部分block(如graph_autofusion),以不同的模式安装时(如:run/full) + # full模式的包先卸载,run模式的包后卸载,确保能够完整卸载。 + do_uninstall "full" "${install_path}" "${filelist_path}" "${PACKAGE}" "${feature_param}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "simple_install") + # 简化安装模式 + do_install "${install_type}" "${install_path}" "${filelist_path}" "${PACKAGE}" "${feature_param}" "" "y" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "simple_uninstall") + # 简化卸载模式 + do_uninstall "full" "${install_path}" "${filelist_path}" "${PACKAGE}" "${feature_param}" "" "y" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "mkdir") + do_create_dirs "all" "$1" "$2" "$3" "${PACKAGE}" "${feature_param}" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "makedir") + do_create_dirs "mkdir" "$1" "$2" "$3" "${PACKAGE}" "${feature_param}" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "copy") + do_copy_files "$1" "$2" "$3" "${PACKAGE}" "${feature_param}" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "chmoddir") + do_chmod_file_dir "$install_type" "$2" "$3" "${feature_param}" "${PACKAGE}" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "restoremod") + do_create_dirs "resetmod" "$1" "$2" "$3" "${PACKAGE}" "${feature_param}" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "remove") + do_remove "$install_type" "$2" "$filelist_path" "${PACKAGE}" "${feature_param}" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + "print") + print_install_content "$1" "$2" "${PRINT_OPERATE_TYPE}" "$3" "${feature_param}" + ret="$?" && [ $ret -ne 0 ] && return $ret + ;; + esac + + return 0 +} + +# 正式命令并加锁 +formal_commands_with_lock() { + local install_path="$2" + local lockfile docker_root install_path_real ret + + if [ "${OPERATE_TYPE}" = "install" ] || [ "${OPERATE_TYPE}" = "uninstall" ]; then + if [ "${WITH_DOCKER_ROOT_PREFIX}" = "y" ]; then + install_path_real="${install_path}" + else + # 移除docker_root右侧的/ + rstrip_path "docker_root" "${DOCKER_ROOT}" + install_path_real="${docker_root}${install_path}" + fi + else + install_path_real="${install_path}" + fi + lockfile="${install_path_real}/ascend.lock" + + if [ ! -d "${install_path_real}" ]; then + # 兼容覆盖安装场景,包安装目录被删除情况 + mkdir -p "${install_path_real}" + # 安装目录设置合适的权限 + change_mod "${install_path_real}" "750" "${INSTALL_FOR_ALL}" + check_ret_error "$?" "Change mod ${install_path_real} failed!" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + # 使用文件描述符9作为并发锁 + ( + flock -n 9 + if [ $? -ne 0 ]; then + log "ERROR" "Get ${install_path_real} lockfile failed! There may be another process also installing in the directory." + exit 1 + fi + formal_commands "$@" + ) 9> "${lockfile}" + ret="$?" + rm -f "${lockfile}" + + if [ $ret -ne 0 ]; then + exit 1 + fi +} + +# 第一个参数为source,标记为source场景,不执行主流程 +[ "$1" = "source" ] && return 0 + +# 全局变量 +# change_mod_and_own_files与change_mod_and_own_dirs函数中会使用 +INSTALL_FOR_ALL="" +SETENV="" +SET_CANN_UNINSTALL="" +IS_UPGRADE="" +IS_RECREATE_SOFTLINK="" +WITH_DOCKER_ROOT_PREFIX="" +FEATURE_EXCLUDE_ALL="n" +REMOVE_INSTALL_INFO="n" # 卸载时移除ascend_install.info文件 +CHIP="all" +FEATURE="all" +INCREMENT="n" # 增量安装 + +OPERATE_TYPE="" +PACKAGE="" +USERNAME="" +USERGROUP="" +VERSION="" +VERSION_DIR="" +VERSION_FILE="" +CUSTOM_OPTIONS="" +# 宿主机打docker包场景,配置docker文件系统根路径 +DOCKER_ROOT="" +# 安装路径 +INSTALL_PATH="" +# 输入的latest_dir +INPUT_LATEST_DIR="" + +while true; do + case "$1" in + --spc-install | -i) + OPERATE_TYPE="spc_install" + shift + ;; + --spc-rollback | -l) + OPERATE_TYPE="spc_rollback" + shift + ;; + --spc-uninstall | -u) + OPERATE_TYPE="spc_uninstall" + shift + ;; + --install) + OPERATE_TYPE="install" + shift + ;; + --uninstall) + OPERATE_TYPE="uninstall" + shift + ;; + --simple-install) + OPERATE_TYPE="simple_install" + shift + ;; + --simple-uninstall) + OPERATE_TYPE="simple_uninstall" + shift + ;; + --copy | -c) + OPERATE_TYPE="copy" + shift + ;; + --mkdir | -m) + OPERATE_TYPE="mkdir" + shift + ;; + --makedir | -d) + OPERATE_TYPE="makedir" + shift + ;; + --chmoddir | -o) + OPERATE_TYPE="chmoddir" + shift + ;; + --restoremod | -e) + OPERATE_TYPE="restoremod" + shift + ;; + --remove | -r) + OPERATE_TYPE="remove" + shift + ;; + --add-cann-uninstall) + OPERATE_TYPE="add-cann-uninstall" + shift + ;; + --del-cann-uninstall) + OPERATE_TYPE="del-cann-uninstall" + shift + ;; + --add-env-rc) + OPERATE_TYPE="add-env-rc" + shift + ;; + --del-env-rc) + OPERATE_TYPE="del-env-rc" + shift + ;; + --pkg-in-dbinfo) + OPERATE_TYPE="pkg-in-dbinfo" + shift + ;; + --add-pkg-blocks) + OPERATE_TYPE="add-pkg-blocks" + shift + ;; + --del-pkg-blocks) + OPERATE_TYPE="del-pkg-blocks" + shift + ;; + --create-latest-softlink) + OPERATE_TYPE="notify_create_softlink" + shift + ;; + --create-package-latest-softlink) + OPERATE_TYPE="notify_create_softlink" + shift + ;; + --remove-latest-softlink) + OPERATE_TYPE="notify_remove_softlink" + shift + ;; + --remove-package-latest-softlink) + OPERATE_TYPE="notify_remove_softlink" + shift + ;; + --print-blocks) + OPERATE_TYPE="print-blocks" + shift + ;; + --print=*) + OPERATE_TYPE="print" + PRINT_OPERATE_TYPE="$(echo "$1" | cut -d"=" -f2)" + shift + ;; + --print| -p) + OPERATE_TYPE="print" + PRINT_OPERATE_TYPE="copy mkdir move" + shift + ;; + --install-path=*) + INSTALL_PATH=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --version=*) + VERSION=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --version-dir=*) + VERSION_DIR=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --version-file=*) + VERSION_FILE=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --latest-dir=*) + INPUT_LATEST_DIR=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --username=*) + USERNAME=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --usergroup=*) + USERGROUP=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --custom-options=*) + CUSTOM_OPTIONS=$(echo "$1" | cut -d"=" -f2-) + shift + ;; + --arch=*) + PKG_ARCH=$(echo "$1" | cut -d"=" -f2-) + shift + if [ "$PKG_ARCH" = "" ]; then + log "ERROR" "The --arch option should not be an empty string." + exit 1 + fi + ;; + --upgrade) + IS_UPGRADE="y" + shift + ;; + --recreate-softlink) + IS_RECREATE_SOFTLINK="y" + shift + ;; + --install_for_all) + INSTALL_FOR_ALL="y" + shift + ;; + --setenv) + SETENV="y" + shift + ;; + --set-cann-uninstall) + SET_CANN_UNINSTALL="y" + shift + ;; + --package=*) + PACKAGE=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --docker-root=*) + DOCKER_ROOT=$(echo "$1" | cut -d"=" -f2) + shift + ;; + --chip=*) + CHIP="$(echo "$1" | cut -d"=" -f2)" + shift + ;; + --feature=*) + FEATURE="$(echo "$1" | cut -d"=" -f2)" + shift + ;; + --with-docker-root-prefix) + WITH_DOCKER_ROOT_PREFIX="y" + shift + ;; + --feature-exclude-all) + FEATURE_EXCLUDE_ALL="y" + shift + ;; + --remove-install-info) + REMOVE_INSTALL_INFO="y" + shift + ;; + --increment) + INCREMENT="y" + shift + ;; + -h | --help) + help_info + exit 0 + ;; + -*) + echo Unrecognized input options : "$1" + help_info + exit 1 + ;; + *) + break + ;; + esac +done + +set_global_vars +env_rc_commands "$@" +dbinfo_commands "$@" +spc_commands "$@" +cann_uninstall_commands "$@" +multi_version_commands "$@" + +if [ $# -lt 3 ]; then + log "ERROR" "It's too few input params: $*" + exit 1 +fi + +formal_commands_with_lock "$@" +exit $? diff --git a/scripts/package/common/sh/multi_version.inc b/scripts/package/common/sh/multi_version.inc new file mode 100644 index 0000000000000000000000000000000000000000..7adce7f7b8157ae6269bcd3eec3a8e19cd6771e2 --- /dev/null +++ b/scripts/package/common/sh/multi_version.inc @@ -0,0 +1,350 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +# 多版本函数库 +# 创建版本目录 +create_version_dir() { + local install_path="$1" + local version_dir="$2" + local username="$3" + local usergroup="$4" + local install_for_all="$5" + local ret + + if [ ! -d "${install_path}/${version_dir}" ]; then + make_dir "${install_path}/${version_dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + # 约束版本号目录权限 + change_mod "${install_path}/${version_dir}" "750" "${install_for_all}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_own "${install_path}/${version_dir}" "${username}:${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 检查版本包安装结果 +check_version_install() { + local install_path="$1" + local version_dir="$2" + local package="$3" + local version_info_path + + get_package_version_info "version_info_path" "$install_path" "$version_dir" "$package" + + if [ ! -f "$version_info_path" ]; then + comm_log "ERROR" "$version_info_path doesn't exist in check version install!" + return 1 + fi + return 0 +} + +# 安装latest管理器 +install_latest_manager() { + local var_path="$1" + shift 1 + sh latest_manager/install.sh --install-path="$var_path" "$@" +} + +# 卸载latest管理器 +uninstall_latest_manager_for_upgrade() { + local var_path="$1" + ${var_path}/manager/uninstall.sh --upgrade +} + +# 升级latest管理器 +upgrade_latest_manager() { + local var_path="$1" + local latest_version_info latest_manager_version local_manager_version + + latest_version_info="$var_path/manager/version.info" + if [ -f "$latest_version_info" ]; then + get_version latest_manager_version "$latest_version_info" + get_version local_manager_version "latest_manager/version.info" + + set_default "latest_manager_version" "$latest_manager_version" "0" + set_default "local_manager_version" "$local_manager_version" "0" + + if [ "$latest_manager_version" -lt "$local_manager_version" ]; then + uninstall_latest_manager_for_upgrade "$var_path" + install_latest_manager "$var_path" "--upgrade" + fi + else + install_latest_manager "$var_path" + fi +} + +get_install_for_all_param() { + local _outvar="$1" + local _install_for_all="$2" + local _result="" + + if [ "$_install_for_all" = "y" ]; then + _result="--install-for-all" + fi + + eval "${_outvar}=\"${_result}\"" +} + +get_docker_root_param() { + local _outvar="$1" + local _docker_root="$2" + local _result="" + + if [ "$_docker_root" != "" ]; then + _result="--docker-root \\\"$_docker_root\\\"" + fi + + eval "${_outvar}=\"${_result}\"" +} + +# 通知latest管理器 +notify_latest_manager() { + local var_path="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local install_for_all="$5" + local docker_root="$6" + local ext_params="$7" + local operation="$8" + local ret package_dir install_for_all_param docker_root_param + + if [ ! -f "$var_path/manager.sh" ]; then + return 1 + fi + + get_package_dir package_dir "$package" + get_install_for_all_param "install_for_all_param" "$install_for_all" + get_docker_root_param "docker_root_param" "$docker_root" + + eval "\"$var_path/manager.sh\"" --version "\"$version\"" --version-dir "\"$version_dir\"" \ + --package "\"$package\"" --package-dir "\"$package_dir\"" \ + "$install_for_all_param" "$docker_root_param" "$ext_params" "$operation" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 通知latest管理器安装完成 +notify_latest_manager_installed() { + local local_manager_version + local ext_params + + get_version local_manager_version "latest_manager/version.info" + set_default "local_manager_version" "$local_manager_version" "0" + + if [ "$INCREMENT" = "y" ]; then + ext_params="--serial $local_manager_version --increment" + else + ext_params="--serial $local_manager_version" + fi + + notify_latest_manager "$@" "$ext_params" "package_installed" +} + +# 通知latest管理器创建软链 +# 老版本全部卸载后,latest回滚到新版本时,会用老版本的install_common_parser.sh, +# 调用新版本的--create-package-latest-softlink,会走到这个流程。 +notify_latest_manager_create_softlink() { + notify_latest_manager "$@" "" "package_create_softlink" +} + +# 通知latest管理器删除软链 +notify_latest_manager_remove_softlink() { + notify_latest_manager "$@" "" "package_remove_softlink" +} + +# 通知latest管理器准备卸载 +notify_latest_manager_pre_uninstall() { + notify_latest_manager "$@" "" "package_pre_uninstall" +} + +# 通知latest管理器卸载完成 +notify_latest_manager_uninstalled() { + local is_recreate_softlink="$1" + local recreate_softlink="" + local ret + shift 1 + + if [ "$is_recreate_softlink" = "y" ]; then + recreate_softlink="--recreate-softlink" + fi + + notify_latest_manager "$@" "$recreate_softlink" "package_uninstalled" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 多版本安装流程 +multi_version_install() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local package="$4" + local feature_param="$5" + local version="$6" + local version_dir="$7" + local username="$8" + local usergroup="$9" + local setenv="${10}" + local is_upgrade="${11}" + local docker_root="${12}" + local custom_options="${13}" + local install_for_all="${14}" + local ret total_ret="0" pkg_running_version version_pair_arr last_version last_version_dir + + create_version_dir "${install_path}" "${version_dir}" "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + version_install "${install_type}" "${install_path}" "${filelist_path}" "${package}" "${feature_param}" \ + "${version_dir}" "${username}" "${usergroup}" "${setenv}" "${is_upgrade}" "${docker_root}" "${custom_options}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + check_version_install "$install_path" "$version_dir" "$package" + ret="$?" && [ $ret -ne 0 ] && return $ret + + make_dir_with_permission "${install_path}/${LATEST_DIR}" "750" "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + make_dir_with_permission "${install_path}/${LATEST_DIR}/var" "750" "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + upgrade_latest_manager "${install_path}/${LATEST_DIR}/var" + ret="$?" && [ $ret -ne 0 ] && return $ret + + notify_latest_manager_installed "$install_path/$LATEST_DIR/var" "$package" \ + "$version" "$version_dir" "$install_for_all" "$docker_root" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return ${total_ret} +} + +# 删除latest下空目录 +del_empty_dirs_in_latest() { + local install_type="$1" + local install_path="$2" + local latest_dir="$3" + local filelist_path="$4" + local feature_param="$5" + local ret + + create_stash_mod "${install_path}/${latest_dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "filter_common_dirs" "reset_mod_dirs_with_stash_mod" "${install_type}" "${install_path}/${latest_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist "filter_common_dirs" "remove_install_dirs" "${install_type}" "${install_path}/${latest_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "reverse" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_stashmod "restore_stash_mod" "${install_path}/${latest_dir}" "reverse" + ret="$?" && [ $ret -ne 0 ] && return $ret + + remove_stash_mod "${install_path}/${latest_dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 多版本卸载流程 +multi_version_uninstall() { + local install_type="$1" + local install_path="$2" + local filelist_path="$3" + local package="$4" + local feature_param="$5" + local version="$6" + local version_dir="$7" + local username="$8" + local usergroup="$9" + local docker_root="${10}" + local custom_options="${11}" + local is_recreate_softlink="${12}" + local tmp_root tmp_filelist_path + local ret total_ret=0 install_path_full="" is_running="" is_upgrade + local running_packages is_final_running="false" + + check_param_not_empty "usergroup" "need set usergroup parameter in multi version uninstall!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + if ! notify_latest_manager_remove_softlink "${install_path}/${LATEST_DIR}/var" "${package}" \ + "${version}" "${version_dir}" "n" "${docker_root}"; then + comm_log "ERROR" "${package} notify latest manager remove softlink in multi version uninstall failed! version is ${version}, version_dir is ${version_dir}." + return 1 + fi + + if ! notify_latest_manager_pre_uninstall "${install_path}/${LATEST_DIR}/var" "${package}" \ + "${version}" "${version_dir}" "n" "${docker_root}"; then + comm_log "ERROR" "${package} notify latest manager pre uninstall in multi version uninstall failed! version is ${version}, version_dir is ${version_dir}." + return 1 + fi + + get_tmp_root "tmp_root" + tmp_filelist_path=$(mktemp "$tmp_root/filelist_XXXXXX" || exit 1) + cp -f "${filelist_path}" "${tmp_filelist_path}" + + if [ $? -ne 0 ]; then + log "ERROR" "cp -f ${filelist_path} ${tmp_filelist_path} failed!" + exit 1 + fi + + del_tmp_filelist="rm -f \"${tmp_filelist_path}\"" + + version_uninstall "${install_type}" "${install_path}" "${filelist_path}" "${package}" "${feature_param}" \ + "${version_dir}" "${username}" "${docker_root}" "${custom_options}" + if [ $? -ne 0 ]; then + eval "${del_tmp_filelist}" + return 1 + fi + + # 切换目录避免使用uninstall.sh脚本,重建子包软链接时,找到不当前路径问题 + # sh: 0: getcwd() failed: No such file or directory + cd "$install_path" + + if ! notify_latest_manager_uninstalled "${is_recreate_softlink}" "${install_path}/${LATEST_DIR}/var" "${package}" \ + "${version}" "${version_dir}" "n" "${docker_root}"; then + comm_log "ERROR" "${package} notify latest manager uninstalled in multi version uninstall failed! version is ${version}, version_dir is ${version_dir}." + eval "${del_tmp_filelist}" + return 1 + fi + + get_running_packages "running_packages" "${install_path}/${LATEST_DIR}" + if [ "${running_packages}" = "" ]; then + # 删除latest下空目录 + del_empty_dirs_in_latest "${install_type}" "${install_path}" "${LATEST_DIR}" "${tmp_filelist_path}" "${feature_param}" + ret="$?" && [ $ret -ne 0 ] && total_ret="1" + fi + + # 删除临时文件tmp_filelist_path + eval "${del_tmp_filelist}" + + # 删除版本空目录 + is_dir_empty "${install_path}/${version_dir}" + if [ $? -eq 0 ]; then + remove_dir_icp "${install_path}/${version_dir}" + ret="$?" && [ $ret -ne 0 ] && total_ret="1" + fi + + # 删除latest空目录 + is_dir_empty "${install_path}/${LATEST_DIR}" + if [ $? -eq 0 ]; then + remove_dir_icp "${install_path}/${LATEST_DIR}" + ret="$?" && [ $ret -ne 0 ] && total_ret="1" + fi + return ${total_ret} +} diff --git a/scripts/package/common/sh/script_operator.inc b/scripts/package/common/sh/script_operator.inc new file mode 100644 index 0000000000000000000000000000000000000000..ae89c33022de1ef8cffa4649c21931b79d0b4086 --- /dev/null +++ b/scripts/package/common/sh/script_operator.inc @@ -0,0 +1,555 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +# 公共脚本操作库 +ENV_SHELL_TYPES="bash csh fish" + +# 检查参数。 +__check_param() { + local name="$1" + local value + + value="$(eval echo \${${name}})" + + if [ "${value}" = "" ]; then + log "ERROR" "need set ${name} parameter!" + exit 1 + fi +} + +# 设置用户家目录路径 +__set_userpath() { + local username="$1" + local docker_root="$2" + + if [ -z "${docker_root}" ] || [ "${docker_root}" = "/" ]; then + userpath="$(eval echo "~${username}")" + else + if [ "${username}" = "root" ]; then + userpath="${docker_root}/root" + else + userpath="${docker_root}/home/${username}" + fi + fi +} + +# 获取setenv.[shell]路径正则 +get_setenv_path_regex() { + local _outvar="$1" + local _package="$2" + local _shell_type="$3" + # setenv传入路径正则规则 + # 必须以/开头(绝对路径) + # 必须以/${package}/bin/setenv.${shell_type}结尾 + local _path_regex="\/\(.\+\/\)\?${_package}\/bin\/setenv.${_shell_type}" + + eval "${_outvar}=\"${_path_regex}\"" +} + +# 创建setenv文件 +__create_setenv_file() { + local file="$1" + local shell_type="$2" + local add_multi_version_param="$3" + local install_path="$4" + local ret + + if [ ! -f "${file}" ]; then + echo "#!/usr/bin/env ${shell_type}" > ${file} + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${add_multi_version_param}" = "true" ]; then + if [ "${shell_type}" = "bash" ]; then + echo "export ASCEND_HOME_PATH=\"${install_path}\"" >> "${file}" + ret="$?" && [ $ret -ne 0 ] && return $ret + elif [ "${shell_type}" = "fish" ]; then + echo "set -gx ASCEND_HOME_PATH \"${install_path}\"" >> "${file}" + ret="$?" && [ $ret -ne 0 ] && return $ret + elif [ "${shell_type}" = "csh" ]; then + echo "setenv ASCEND_HOME_PATH \"${install_path}\"" >> "${file}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + fi + fi + return 0 +} + +# 是否存在ASCEND_HOME_PATH环境变量 +has_ascend_home_path_env() { + local file="$1" + [ ! -f "${file}" ] && return 0 + grep "\" "${file}" > /dev/null 2>&1 +} + +# 添加ASCEND_HOME_PATH环境变量 +add_ascend_home_path_env() { + local file="$1" + local shell_type="$2" + local install_path="$3" + + if [ "${shell_type}" = "bash" ]; then + sed -i "1aexport ASCEND_HOME_PATH=\"${install_path}\"" "${file}" + elif [ "${shell_type}" = "fish" ]; then + sed -i "1aset -gx ASCEND_HOME_PATH \"${install_path}\"" "${file}" + elif [ "${shell_type}" = "csh" ]; then + sed -i "1asetenv ASCEND_HOME_PATH \"${install_path}\"" "${file}" + fi +} + +# 删除rcfile中的source +__remove_path_regex() { + local path_regex="$1" + local rcfile="$2" + + if [ -f "${rcfile}" ]; then + sed -i "/source ${path_regex}\( \"multi_version\"\)\?$/d" "${rcfile}" + if [ $? -ne 0 ]; then + log "ERROR" "remove ${rcfile} source command failed!" + exit 1 + fi + fi +} + +# 获取setenv.${shell_type}文件路径 +get_setenv_filepath() { + local _outvar="$1" + local _install_path="$2" + local _shell_type="$3" + + eval "${_outvar}=\"${_install_path}/bin/setenv.${_shell_type}\"" +} + +# setenv.[shell]总脚本中添加一条语句 +add_setenv_cmd() { + local install_path="$1" + local setenv_filepath="$2" + local package="$3" + local shell_type="$4" + local username="$5" + local usergroup="$6" + local add_multi_version_param="$7" + local path_regex config_path multi_version_param ret + + get_setenv_path_regex "path_regex" "${package}" "${shell_type}" + + get_setenv_filepath "config_path" "$install_path" "$shell_type" + __create_setenv_file "${config_path}" "${shell_type}" "${add_multi_version_param}" "${install_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_own "${config_path}" "${username}:${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_mod "${config_path}" "${SETENV_WRITEABLE_MOD}" "" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_path_regex "${path_regex}" "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${add_multi_version_param}" = "true" ]; then + multi_version_param=" \"multi_version\"" + fi + + if [ "${shell_type}" = "bash" ] || [ "${shell_type}" = "fish" ]; then + echo "source ${setenv_filepath}${multi_version_param}" >> "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + elif [ "${shell_type}" = "csh" ]; then + echo "set argv=(\"${setenv_filepath}\"${multi_version_param}); source ${setenv_filepath}" >> "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + change_mod "${config_path}" "${SETENV_MOD}" "${INSTALL_FOR_ALL}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 修改路径的own +__chown_path() { + local path="$1" + local username="$2" + local usergroup="$3" + + if [ "${username}" != "" ] && [ "${usergroup}" != "" ]; then + chown -h "${username}:${usergroup}" "${path}" + if [ $? -ne 0 ]; then + log "ERROR" "${path} chown failed!" + exit 1 + fi + fi + + return 0 +} + +# 创建配置所在目录 +__create_config_dir() { + local dir="$1" + local username="$2" + local usergroup="$3" + local ret + + if [ ! -d "${dir}" ]; then + mkdir -p "${dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __chown_path "${dir}" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# 创建配置文件 +__create_config_file() { + local file="$1" + local username="$2" + local usergroup="$3" + local ret + + if [ ! -f "${file}" ]; then + touch "${file}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __chown_path "${file}" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# 添加source setenv.[shell]脚本到rc文件中 +add_env_rc() { + local install_path="$1" + local setenv_filepath="$2" + local package="$3" + local shell_type="$4" + local setenv="$5" + local username="$6" + local usergroup="$7" + local add_multi_version_param="$8" + local docker_root="$9" + local path_suffix="${package}/bin/setenv.${shell_type}" + local path_regex + local matched + local userpath + local config_path + local ret + + __check_param "package" + __check_param "username" + __check_param "usergroup" + + echo "${shell_type}" | grep -E "^(bash|fish|csh)$" > /dev/null + if [ $? -ne 0 ]; then + log "ERROR" "shell type ${shell_type} not support!" + exit 1 + fi + + get_setenv_path_regex "path_regex" "${package}" "${shell_type}" + + matched="$(echo "${setenv_filepath}" | sed -n "/^${path_regex}$/p")" + if [ -z "${matched}" ]; then + log "ERROR" "setenv filepath is illegal, should endswith ${path_suffix}" + exit 1 + fi + + if [ "${setenv}" = "y" ]; then + __set_userpath "${username}" "${docker_root}" + + if [ "${shell_type}" = "bash" ]; then + config_path="${userpath}/.bashrc" + __create_config_dir "${userpath}" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __create_config_file "${config_path}" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_path_regex "${path_regex}" "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "source ${setenv_filepath}" >> "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + elif [ "${shell_type}" = "fish" ]; then + config_path="${userpath}/.config/fish/config.fish" + __create_config_dir "${userpath}" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __create_config_dir "${userpath}/.config" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __create_config_dir "${userpath}/.config/fish" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __create_config_file "${config_path}" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_path_regex "${path_regex}" "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "source ${setenv_filepath}" >> "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + elif [ "${shell_type}" = "csh" ]; then + config_path="${userpath}/.cshrc" + __create_config_dir "${userpath}" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __create_config_file "${config_path}" "${username}" "${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_path_regex "${path_regex}" "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "set argv=(\"${setenv_filepath}\"); source ${setenv_filepath}" >> "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + fi + + if [ ! -d "${install_path}/bin" ]; then + # 如果bin目录不存在,则不处理 + return 0 + fi + + add_setenv_cmd "${install_path}" "${setenv_filepath}" "${package}" "${shell_type}" "${username}" "${usergroup}" "${add_multi_version_param}" +} + +# 删除setenv文件,如果已经没有setenv内容 +__remove_setenv_file_if_no_content() { + local file="$1" + local shell_type="$2" + local num + + if [ ! -f "${file}" ]; then + return 0 + fi + + num=$(grep "setenv.${shell_type}" ${file} | wc -l) + if [ ${num} -eq 0 ]; then + rm -f "${file}" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "WARNING" "Delete file:${file} failed, please delete it by yourself." + fi + fi +} + +# 从rc文件中删除source setenv.[shell] +del_env_rc() { + local install_path="$1" + local setenv_filepath="$2" + local shell_type="$3" + local username="$4" + local docker_root="$5" + local path_regex + local userpath + local config_path + local oldmod + + __check_param "username" + + echo "${shell_type}" | grep -E "^(bash|fish|csh)$" > /dev/null + if [ $? -ne 0 ]; then + log "ERROR" "shell type ${shell_type} not support!" + exit 1 + fi + + __set_userpath "${username}" "${docker_root}" + + # 将路径中的/转换为\/ + path_to_regex "path_regex" "${setenv_filepath}" + + if [ "${shell_type}" = "bash" ]; then + __remove_path_regex "${path_regex}" "${userpath}/.bashrc" + ret="$?" && [ $ret -ne 0 ] && return $ret + elif [ "${shell_type}" = "fish" ]; then + __remove_path_regex "${path_regex}" "${userpath}/.config/fish/config.fish" + ret="$?" && [ $ret -ne 0 ] && return $ret + elif [ "${shell_type}" = "csh" ]; then + __remove_path_regex "${path_regex}" "${userpath}/.cshrc" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + get_setenv_filepath "config_path" "$install_path" "$shell_type" + + if [ ! -f "${config_path}" ]; then + # 如果文件不存在,则不处理 + return 0 + fi + + get_file_mod "oldmod" "${config_path}" + change_mod "${config_path}" "${SETENV_WRITEABLE_MOD}" "" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_path_regex "${path_regex}" "${config_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_mod "${config_path}" "${oldmod}" "" + ret="$?" && [ $ret -ne 0 ] && return $ret + + __remove_setenv_file_if_no_content "${config_path}" "${shell_type}" +} + +# 移除路径中的docker_root +remove_path_docker_root() { + local _outvar="$1" + local _path="$2" + local _docker_root="$3" + local _path_rpdr="$(echo "${_path}" | sed "s/^.\{${#_docker_root}\}//")" + + eval "${_outvar}=\"${_path_rpdr}\"" +} + +# 获取脚本路径与脚本真实路径(docker_root) +get_shell_path_and_shell_path_real() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + local _shell_filename="$4" + local _docker_root="$5" + local _package_dirpath _shell_path _shell_path_real + + get_package_dirpath "_package_dirpath" "${_package}" + _shell_path_real="${_install_path}/${_package_dirpath}/bin/${_shell_filename}" + + if [ "${_docker_root}" != "" ]; then + # 移除脚本路径中的docker_root前缀 + remove_path_docker_root "_shell_path" "${_shell_path_real}" "${_docker_root}" + else + _shell_path="${_shell_path_real}" + fi + + eval "${_outvar}=\"${_shell_path} ${_shell_path_real}\"" +} + +# 增加prereq_check +add_prereq_check() { + local install_path="$1" + local package="$2" + local username="$3" + local usergroup="$4" + local docker_root="$5" + local ret + + for type in ${ENV_SHELL_TYPES}; do + local shell_path_pair shell_path shell_path_real + + get_shell_path_and_shell_path_real "shell_path_pair" "${install_path}" "${package}" "prereq_check.${type}" "${docker_root}" + __index_list "${shell_path_pair}" 0 "shell_path" 1 "shell_path_real" + [ ! -f "${shell_path_real}" ] && continue + + local common_path=${install_path}/bin/prereq_check.${type} + local path_regex="\/\(.\+\/\)\?${package}\/bin\/prereq_check.${type}" + if [ -f "${common_path}" ]; then + chmod u+w ${common_path} + + sed -i "/^${path_regex}$/d" ${common_path} + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "${shell_path}" >> ${common_path} + ret="$?" && [ $ret -ne 0 ] && return $ret + + chmod u-w ${common_path} + else + echo "#!/usr/bin/env ${type}" > ${common_path} + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "${shell_path}" >> ${common_path} + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_mod "${common_path}" "${SETENV_MOD}" "${INSTALL_FOR_ALL}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + change_own "${common_path}" "${username}:${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + done + + return 0 +} + +# 删除prereq_check +del_prereq_check() { + local install_path="$1" + local package="$2" + local docker_root="$3" + local ret + + for type in ${ENV_SHELL_TYPES}; do + local shell_path_pair shell_path shell_path_real + + get_shell_path_and_shell_path_real "shell_path_pair" "${install_path}" "${package}" "prereq_check.${type}" "${docker_root}" + __index_list "${shell_path_pair}" 0 "shell_path" 1 "shell_path_real" + + local common_path="${install_path}/bin/prereq_check.${type}" + + [ ! -f "${common_path}" ] && continue + + chmod u+w "${common_path}" + local path_regex="\/\(.\+\/\)\?${package}\/bin\/prereq_check.${type}" + + sed -i "/^${path_regex}$/d" "${common_path}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + chmod u-w "${common_path}" + + local num=$(grep -r "prereq_check.${type}" "${common_path}" | wc -l) + if [ "${num}" -eq 0 ]; then + rm -f "${common_path}" + fi + done + + return 0 +} + +# 设置环境变量 +add_setenv() { + local install_path="$1" + local package="$2" + local setenv="$3" + local username="$4" + local usergroup="$5" + local add_multi_version_param="$6" + local docker_root="$7" + + for type in ${ENV_SHELL_TYPES}; do + local shell_path_pair shell_path shell_path_real + + get_shell_path_and_shell_path_real "shell_path_pair" "${install_path}" "${package}" "setenv.${type}" "${docker_root}" + __index_list "${shell_path_pair}" 0 "shell_path" 1 "shell_path_real" + [ ! -f "${shell_path_real}" ] && continue + + add_env_rc "${install_path}" "${shell_path}" "${package}" "${type}" "${setenv}" "${username}" "${usergroup}" "${add_multi_version_param}" "${docker_root}" + if [ $? -ne 0 ]; then + log "ERROR" "failed to set ${package} ${type} env." + return 1 + fi + done + + return 0 +} + +# 删除环境变量 +del_setenv() { + local install_path="$1" + local package="$2" + local username="$3" + local docker_root="$4" + + for type in $ENV_SHELL_TYPES; do + local shell_path_pair shell_path shell_path_real + + get_shell_path_and_shell_path_real "shell_path_pair" "${install_path}" "${package}" "setenv.${type}" "${docker_root}" + __index_list "${shell_path_pair}" 0 "shell_path" 1 "shell_path_real" + + del_env_rc "${install_path}" "${shell_path}" "${type}" "${username}" "${docker_root}" + if [ $? -ne 0 ]; then + log "ERROR" "failed to unset ${package} ${type} env." + return 1 + fi + done + + return 0 +} diff --git a/scripts/package/common/sh/version_cfg.inc b/scripts/package/common/sh/version_cfg.inc new file mode 100644 index 0000000000000000000000000000000000000000..c5245d121c8e7df00c0ef2eae01efc6ac7d3d741 --- /dev/null +++ b/scripts/package/common/sh/version_cfg.inc @@ -0,0 +1,1027 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +# 版本状态配置文件处理 +# 版本状态配置文件格式为 +# # version: 1.0 +# runtime_running_version=[1.80:CANN-1.80] +# compiler_running_version=[1.80:CANN-1.80] +# toolkit_running_version=[1.80:CANN-1.80] +# fwkplugin_running_version=[1.80:CANN-1.80] +# runtime_installed_version=[1.79:CANN-1.79][1.80:CANN-1.80] +# compiler_installed_version=[1.79:CANN-1.79][1.80:CANN-1.80][1.81:CANN-1.81] +# toolkit_installed_version=[1.79:CANN-1.79][1.80:CANN-1.80][1.81:CANN-1.81] +# fwkplugin_installed_version=[1.79:CANN-1.79][1.80:CANN-1.80][1.81:CANN-1.81] + +# 子包会source本文件,本文件中调用的函数,都需要在文件内找到定义 + +# latest目录名 +LATEST_DIR="latest" + +# 配置版本号 +_CFG_VERSION="1.0" + +# 获取列表索引值 +__index_list_by_cut() { + local _list_ilbc="$1" + local _cnt_ilbc _value_ilbc + shift + + while true; do + if [ $# -eq 0 ]; then + return 0 + fi + _cnt_ilbc="${1}" && _cnt_ilbc=$((_cnt_ilbc+1)) + _value_ilbc="$(echo "${_list_ilbc}" | cut -d' ' -f"${_cnt_ilbc}")" + eval "${2}=\"${_value_ilbc}\"" + shift 2 + done + + return 0 +} + +# 获取版本状态配置路径 +get_version_cfg_path() { + local _outvar="$1" + local _dirpath="$2" + eval "${_outvar}=\"${_dirpath}/version.cfg\"" +} + +# 获取版本状态配置新路径 +get_version_cfg_new_path() { + local _outvar="$1" + local _dirpath="$2" + eval "${_outvar}=\"${_dirpath}/version.cfg.new\"" +} + +# 解析配置行 +parse_cfg_line() { + local _outvar="$1" + local _cfg_line="$2" + local _cfg_items_pcl + + _cfg_items_pcl=$(echo "${_cfg_line}" | awk ' + function join(items, len, sep, result, i) { + if (len >= 1) { + result = items[1] + for (i = 2; i <= len; i++) { + result = sprintf("%s%s%s", result, sep, items[i]) + } + return result + } + return "" + } + + /^[A-Za-z0-9_-]+_version=/ { + split($0, line_tokens, "=") + len_attr_tokens = split(line_tokens[1], attr_tokens, "_") + len_package_names = 0 + for (i = 1; i < len_attr_tokens - 1; i++) { + len_package_names++ + package_names[len_package_names] = attr_tokens[i] + } + package_name = join(package_names, len_package_names, "_") + attr_type = attr_tokens[len_attr_tokens-1] + value = line_tokens[2] + + printf("%s %s %s", package_name, attr_type, value) + } + ') + eval "${_outvar}=\"${_cfg_items_pcl}\"" +} + +# 解析配置版本号列表 +unpack_versions() { + local _outvar="$1" + local _value="$2" + + local _versions="$(echo "${_value}" | sed 's/\[//g')" + _versions="$(echo "${_versions}" | sed 's/\]/ /g')" + _versions="$(echo ${_versions})" # strip + eval "${_outvar}=\"${_versions}\"" +} + +# 打包配置版本号列表 +pack_versions() { + local _outvar="$1" + local _versions="$2" + + local _value="$(echo "${_versions}" | sed 's/ /\]\[/g')" + eval "${_outvar}=\"[${_value}]\"" +} + +# 解析版本序对 +unpack_version_pair() { + local _outvar="$1" + local _value="$2" + + eval "${_outvar}=\"$(echo "${_value}" | tr ':' ' ')\"" +} + +# 打包运行版本配置 +pack_running_version() { + local _outvar="$1" + local _package="$2" + local _version="$3" + local _version_dir="$4" + + local _version_str + pack_versions "_version_str" "${_version}:${_version_dir}" + eval "${_outvar}=\"${_package}_running_version=${_version_str}\"" +} + +# 打包升级版本配置 +pack_upgrade_version() { + local _outvar="$1" + local _package="$2" + local _version="$3" + local _version_dir="$4" + + local _version_str + pack_versions "_version_str" "${_version}:${_version_dir}" + eval "${_outvar}=\"${_package}_upgrade_version=${_version_str}\"" +} + +# 检查配置版本 +check_cfg_version() { + local filepath="$1" + local version + + if [ ! -f "${filepath}" ]; then + return 0 + fi + + version=$(sed -n '1p' "${filepath}" | cut -d" " -f3) + if [ "${version}" != "${_CFG_VERSION}" ]; then + return 1 + fi + return 0 +} + +# 输出配置版本错误 +error_check_cfg_version() { + local filepath="$1" + log "ERROR" "check ${filepath} version failed!" +} + +# 检查配置版本并输出报错日志 +check_cfg_version_with_log() { + local filepath="$1" + local ret + + check_cfg_version "${filepath}" + ret="$?" + if [ ${ret} -ne 0 ]; then + error_check_cfg_version "${filepath}" + return ${ret} + fi + return 0 +} + +# 添加配置版本注释 +add_cfg_version_comment() { + local filepath="$1" + sed -i "1i # version: ${_CFG_VERSION}" "${filepath}" +} + +# 移除子包版本 +unset_package_version() { + local dirpath="$1" + local package="$2" + local target_type="$3" + local filepath filepath_new line cfg_items package_name attr_type + local cleanup="" ret mod + + get_version_cfg_path "filepath" "${dirpath}" + get_version_cfg_new_path "filepath_new" "${dirpath}" + + # 版本状态配置文件不存在则正常退出 + if [ ! -f "${filepath}" ]; then + return 0 + fi + + check_cfg_version_with_log "${filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + # 保存当前目录的权限 + get_file_mod "mod" "${dirpath}" + + # 添加目录写权限 + chmod u+w "${dirpath}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 恢复权限 + cleanup="chmod ${mod} \"${dirpath}\"" + + rm -f "${filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${filepath_new} failed!" + eval "${cleanup}" + return 1 + fi + + while read line; do + parse_cfg_line "cfg_items" "${line}" + [ "${cfg_items}" = "" ] && continue + + __index_list_by_cut "${cfg_items}" 0 "package_name" 1 "attr_type" + + if [ "${attr_type}" = "${target_type}" ]; then + if [ "${package_name}" != "${package}" ]; then + echo "${line}" >> "${filepath_new}" + fi + else + echo "${line}" >> "${filepath_new}" + fi + done < "${filepath}" + + if [ -f "${filepath_new}" ]; then + add_cfg_version_comment "${filepath_new}" + mv -f "${filepath_new}" "${filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "replace ${filepath} failed!" + eval "${cleanup}" + return 1 + fi + else + rm -f "${filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${filepath} failed!" + eval "${cleanup}" + return 1 + fi + fi + + eval "${cleanup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 获取子包版本 +get_package_version_version_cfg() { + local _outvar="$1" + local _dirpath="$2" + local _package="$3" + local _target_type="$4" + local _filepath _version_gpv + + get_version_cfg_path "_filepath" "${_dirpath}" + + if [ ! -f "${_filepath}" ]; then + eval "${_outvar}=\"\"" + return 0 + fi + + check_cfg_version "${_filepath}" + if [ $? -ne 0 ]; then + eval "${_outvar}=\"\"" + return 1 + fi + + _version_gpv="$(grep "^${_package}_${_target_type}_version=" "${_filepath}" | cut -d= -f2-)" + if [ "${_version_gpv}" != "" ]; then + unpack_versions "_version_gpv" "${_version_gpv}" + fi + + eval "${_outvar}=\"${_version_gpv}\"" + return 0 +} + +# 设置运行子包版本 +set_running_package_version() { + local dirpath="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local filepath filepath_new line cfg_items package_name attr_type running_version + local setted="false" cleanup="" ret mod + + get_version_cfg_path "filepath" "${dirpath}" + get_version_cfg_new_path "filepath_new" "${dirpath}" + + check_cfg_version_with_log "${filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + pack_running_version "running_version" "${package}" "${version}" "${version_dir}" + + # 保存当前目录的权限 + get_file_mod "mod" "${dirpath}" + + # 添加目录写权限 + chmod u+w "${dirpath}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 恢复权限 + cleanup="chmod ${mod} \"${dirpath}\"" + + rm -f "${filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${filepath_new} failed!" + eval "${cleanup}" + return 1 + fi + + touch "${filepath}" + while read line; do + parse_cfg_line "cfg_items" "${line}" + [ "${cfg_items}" = "" ] && continue + + __index_list_by_cut "${cfg_items}" 0 "package_name" 1 "attr_type" + + if [ "${attr_type}" = "running" ]; then + if [ "${package_name}" = "${package}" ]; then + if [ "${setted}" = "false" ]; then + echo "${running_version}" >> "${filepath_new}" + setted="true" + fi + else + echo "${line}" >> "${filepath_new}" + fi + elif [ "${attr_type}" = "upgrade" ]; then + if [ "${setted}" = "false" ]; then + echo "${running_version}" >> "${filepath_new}" + setted="true" + fi + echo "${line}" >> "${filepath_new}" + elif [ "${attr_type}" = "installed" ]; then + if [ "${setted}" = "false" ]; then + echo "${running_version}" >> "${filepath_new}" + setted="true" + fi + echo "${line}" >> "${filepath_new}" + else + echo "${line}" >> "${filepath_new}" + fi + done < "${filepath}" + + if [ "${setted}" = "false" ]; then + echo "${running_version}" >> "${filepath_new}" + setted="true" + fi + + add_cfg_version_comment "${filepath_new}" + mv -f "${filepath_new}" "${filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "replace ${filepath} failed!" + eval "${cleanup}" + return 1 + fi + + eval "${cleanup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 移除子包运行版本 +unset_running_package() { + local dirpath="$1" + local package="$2" + + unset_package_version "${dirpath}" "${package}" "running" +} + +# 获取子包运行版本 +get_running_package_version() { + local _outvar="$1" + local _dirpath="$2" + local _package="$3" + + get_package_version_version_cfg "${_outvar}" "${_dirpath}" "${_package}" "running" +} + +# 设置子包升级版本 +set_upgrade_package_version() { + local dirpath="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local filepath filepath_new line cfg_items package_name attr_type upgrade_version + local setted="false" cleanup="" ret mod + + get_version_cfg_path "filepath" "${dirpath}" + get_version_cfg_new_path "filepath_new" "${dirpath}" + + check_cfg_version_with_log "${filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + pack_upgrade_version "upgrade_version" "${package}" "${version}" "${version_dir}" + + # 保存当前目录的权限 + get_file_mod "mod" "${dirpath}" + + # 添加目录写权限 + chmod u+w "${dirpath}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 恢复权限 + cleanup="chmod ${mod} \"${dirpath}\"" + + rm -f "${filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${filepath_new} failed!" + eval "${cleanup}" + return 1 + fi + + touch "${filepath}" + while read line; do + parse_cfg_line "cfg_items" "${line}" + [ "${cfg_items}" = "" ] && continue + + __index_list_by_cut "${cfg_items}" 0 "package_name" 1 "attr_type" + + if [ "${attr_type}" = "upgrade" ]; then + if [ "${package_name}" = "${package}" ]; then + if [ "${setted}" = "false" ]; then + echo "${upgrade_version}" >> "${filepath_new}" + setted="true" + fi + else + echo "${line}" >> "${filepath_new}" + fi + elif [ "${attr_type}" = "installed" ]; then + if [ "${setted}" = "false" ]; then + echo "${upgrade_version}" >> "${filepath_new}" + setted="true" + fi + echo "${line}" >> "${filepath_new}" + else + echo "${line}" >> "${filepath_new}" + fi + done < "${filepath}" + + if [ "${setted}" = "false" ]; then + echo "${upgrade_version}" >> "${filepath_new}" + setted="true" + fi + + add_cfg_version_comment "${filepath_new}" + mv -f "${filepath_new}" "${filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "replace ${filepath} failed!" + eval "${cleanup}" + return 1 + fi + + eval "${cleanup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 移除子包升级版本 +unset_upgrade_package() { + local dirpath="$1" + local package="$2" + unset_package_version "${dirpath}" "${package}" "upgrade" +} + +# 获取子包升级版本 +get_upgrade_package_version() { + local _outvar="$1" + local _dirpath="$2" + local _package="$3" + + get_package_version_version_cfg "${_outvar}" "${_dirpath}" "${_package}" "upgrade" +} + +# 包版本是否为某状态 +is_package_version_status() { + local _outvar="$1" + local _latest_path="$2" + local _package="$3" + local _version="$4" + local _version_dir="$5" + local _target_type="$6" + local _pkg_status_version + local _ret _result_ipvs="" + + eval "${_outvar}=\"\"" + + get_package_version_version_cfg "_pkg_status_version" "${_latest_path}" "${_package}" "${_target_type}" + _ret="$?" && [ $_ret -ne 0 ] && return $_ret + + if [ "${_pkg_status_version}" = "${_version}:${_version_dir}" ]; then + _result_ipvs="true" + else + _result_ipvs="false" + fi + + eval "${_outvar}=\"${_result_ipvs}\"" +} + +# 包版本是否running +is_package_version_running() { + local _outvar="$1" + local _latest_path="$2" + local _package="$3" + local _version="$4" + local _version_dir="$5" + + is_package_version_status "${_outvar}" "${_latest_path}" "${_package}" "${_version}" "${_version_dir}" "running" +} + +# 包版本是否upgrade +is_package_version_upgrade() { + local _outvar="$1" + local _latest_path="$2" + local _package="$3" + local _version="$4" + local _version_dir="$5" + + is_package_version_status "${_outvar}" "${_latest_path}" "${_package}" "${_version}" "${_version_dir}" "upgrade" +} + +# 添加安装子包版本 +add_installed_package_version() { + local dirpath="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local filepath filepath_new line cfg_items package_name attr_type value versions matched version_str + local setted="false" + + get_version_cfg_path "filepath" "${dirpath}" + get_version_cfg_new_path "filepath_new" "${dirpath}" + + check_cfg_version_with_log "${filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + rm -f "${filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${filepath_new} failed!" + return 1 + fi + + pack_versions "version_str" "${version}:${version_dir}" + + touch "${filepath}" + while read line; do + parse_cfg_line "cfg_items" "${line}" + [ "${cfg_items}" = "" ] && continue + + __index_list_by_cut "${cfg_items}" 0 "package_name" 1 "attr_type" 2 "value" + + if [ "${attr_type}" = "installed" ] && [ "${package_name}" = "${package}" ]; then + unpack_versions "versions" "${value}" + __item_in_list "matched" "${version}:${version_dir}" ${versions} + if [ "${matched}" = "true" ]; then + echo "${line}" >> "${filepath_new}" + else + echo "${line}${version_str}" >> "${filepath_new}" + fi + setted="true" + else + echo "${line}" >> "${filepath_new}" + fi + done < "${filepath}" + + if [ "${setted}" = "false" ]; then + echo "${package}_installed_version=${version_str}" >> "${filepath_new}" + setted="true" + fi + + add_cfg_version_comment "${filepath_new}" + mv -f "${filepath_new}" "${filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "replace ${filepath} failed!" + return 1 + fi +} + +# 删除安装子包版本 +del_installed_package_version() { + local dirpath="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local filepath filepath_new line cfg_items package_name attr_type value versions len_versions + + get_version_cfg_path "filepath" "${dirpath}" + get_version_cfg_new_path "filepath_new" "${dirpath}" + + # 版本状态配置文件不存在则正常退出 + if [ ! -f "${filepath}" ]; then + return 0 + fi + + check_cfg_version_with_log "${filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + rm -f "${filepath_new}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${filepath_new} failed!" + return 1 + fi + + while read line; do + parse_cfg_line "cfg_items" "${line}" + [ "${cfg_items}" = "" ] && continue + + __index_list_by_cut "${cfg_items}" 0 "package_name" 1 "attr_type" 2 "value" + + if [ "${attr_type}" = "installed" ] && [ "${package_name}" = "${package}" ]; then + unpack_versions "versions" "${value}" + versions="$(__remove_item_in_list "${version}:${version_dir}" "${versions}")" + __length_list "${versions}" "len_versions" + if [ ${len_versions} -gt 0 ]; then + pack_versions "value" "${versions}" + echo "${package}_installed_version=${value}" >> "${filepath_new}" + fi + else + echo "${line}" >> "${filepath_new}" + fi + done < "${filepath}" + + if [ -f "${filepath_new}" ]; then + add_cfg_version_comment "${filepath_new}" + mv -f "${filepath_new}" "${filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "replace ${filepath} failed!" + return 1 + fi + else + rm -f "${filepath}" + if [ $? -ne 0 ]; then + log "ERROR" "delete ${filepath} failed!" + return 1 + fi + fi + return 0 +} + +# 获取子包版本 +get_installed_package_versions() { + local _outvar="$1" + local _dirpath="$2" + local _package="$3" + local _filepath _value _new_versions_gipv + + get_version_cfg_path "_filepath" "${_dirpath}" + + if [ ! -f "${_filepath}" ]; then + eval "${_outvar}=\"\"" + return 0 + fi + + check_cfg_version "${_filepath}" + if [ $? -ne 0 ]; then + eval "${_outvar}=\"\"" + return 1 + fi + + _value="$(grep "^${_package}_installed_version=" "${_filepath}" | cut -d= -f2-)" + unpack_versions "_new_versions_gipv" "${_value}" + __reverse_list "_new_versions_gipv" "${_new_versions_gipv}" + + eval "${_outvar}=\"${_new_versions_gipv}\"" +} + +# 获取子包最后一次的安装版本 +get_package_last_installed_version() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + local _versions_gpliv="" _version_gpliv="" _ret + + eval "${_outvar}=\"\"" + + get_installed_package_versions "_versions_gpliv" "${_install_path}/${LATEST_DIR}" "${_package}" + _ret="$?" && [ ${_ret} -ne 0 ] && return ${_ret} + + [ "${_versions_gpliv}" = "" ] && return 0 + + __index_list_by_cut "${_versions_gpliv}" 0 "_version_gpliv" + + eval "${_outvar}=\"${_version_gpliv}\"" +} + + +# 获取子包最后一次的安装版本目录 +# 如果不存在上次安装版本,则返回空字符串 +get_package_last_installed_version_dir() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + local _version_pair _version_pair_arr _version_dir_gplivd="" _ret + + eval "${_outvar}=\"\"" + + get_package_last_installed_version "_version_pair" "${_install_path}" "${_package}" + _ret="$?" && [ ${_ret} -ne 0 ] && return ${_ret} + + unpack_version_pair "_version_pair_arr" "${_version_pair}" + __index_list_by_cut "${_version_pair_arr}" 1 "_version_dir_gplivd" + + eval "${_outvar}=\"${_version_dir_gplivd}\"" +} + +# 获取子包最后一次安装的install.info路径 +# 如果不存在上次安装版本,则返回空字符串 +get_package_last_install_info() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + local _version_dir="" _install_info="" _ret + + eval "${_outvar}=\"\"" + + get_package_last_installed_version_dir "_version_dir" "${_install_path}" "${_package}" + _ret="$?" && [ ${_ret} -ne 0 ] && return ${_ret} + + [ "${_version_dir}" = "" ] && return 0 + + get_package_install_info "_install_info" "${_install_path}" "${_version_dir}" "${_package}" + + eval "${_outvar}=\"${_install_info}\"" +} + +get_package_version_dir() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + local _target_type="$4" + local _version_pair _version_pair_arr _version_dir_gprvd="" _ret + + eval "${_outvar}=\"\"" + + get_package_version_version_cfg "_version_pair" "${_install_path}/${LATEST_DIR}" "${_package}" "${_target_type}" + _ret="$?" && [ ${_ret} -ne 0 ] && return ${_ret} + + if [ "${_version_pair}" = "" ] && [ "${_target_type}" = "upgrade" ]; then + get_package_version_version_cfg "_version_pair" "${_install_path}/${LATEST_DIR}" "${_package}" "running" + _ret="$?" && [ ${_ret} -ne 0 ] && return ${_ret} + fi + + [ "${_version_pair}" = "" ] && return 0 + + unpack_version_pair "_version_pair_arr" "${_version_pair}" + __index_list_by_cut "${_version_pair_arr}" 1 "_version_dir_gprvd" + + eval "${_outvar}=\"${_version_dir_gprvd}\"" +} + +get_package_install_message() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + local _target_type="$4" + local _version_dir_gpim="" _install_info_gpim="" _ret + + eval "${_outvar}=\"\"" + + get_package_version_dir "_version_dir_gpim" "${_install_path}" "${_package}" "${_target_type}" + _ret="$?" && [ ${_ret} -ne 0 ] && return ${_ret} + + [ "${_version_dir_gpim}" = "" ] && return 0 + + get_package_install_info "_install_info_gpim" "${_install_path}" "${_version_dir_gpim}" "${_package}" + + eval "${_outvar}=\"${_install_info_gpim}\"" +} + +# 获取子包的运行版本目录 +# 如果不存在运行版本,则返回空字符串 +get_package_running_version_dir() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + + get_package_version_dir "${_outvar}" "${_install_path}" "${_package}" "running" +} + +# 获取子包运行版本的install.info路径 +# 如果不存在运行版本,则返回空字符串 +get_package_running_install_info() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + + get_package_install_message "${_outvar}" "${_install_path}" "${_package}" "running" +} + +# 获取子包的升级版本目录 +# 如果不存在升级版本,则返回运行版本目录 +# 如果也不存在运行版本,则返回空字符串 +get_package_upgrade_version_dir() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + + get_package_version_dir "${_outvar}" "${_install_path}" "${_package}" "upgrade" +} + +# 获取子包升级版本的install.info路径 +# 如果不存在升级版本,则返回运行版本的install.info路径 +# 如果也不存在运行版本,则返回空字符串 +get_package_upgrade_install_info() { + local _outvar="$1" + local _install_path="$2" + local _package="$3" + + get_package_install_message "${_outvar}" "${_install_path}" "${_package}" "upgrade" +} + +# 获取所有运行包 +get_running_packages() { + local _outvar="$1" + local _dirpath="$2" + local _filepath _line _cfg_items _package_name_grp _attr_type_grp _packages="" + + eval "${_outvar}=\"\"" + + get_version_cfg_path "_filepath" "${_dirpath}" + + if [ ! -f "${_filepath}" ]; then + return 0 + fi + + check_cfg_version "${_filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + while read _line; do + parse_cfg_line "_cfg_items" "${_line}" + [ "${_cfg_items}" = "" ] && continue + + __index_list_by_cut "${_cfg_items}" 0 "_package_name_grp" 1 "_attr_type_grp" + + if [ "${_attr_type_grp}" = "running" ]; then + if [ "${_packages}" = "" ]; then + _packages="${_package_name_grp}" + else + _packages="${_packages} ${_package_name_grp}" + fi + fi + done < "${_filepath}" + + eval "${_outvar}=\"${_packages}\"" +} + +# 根据版本目录获取版本号 +get_version_by_version_dir() { + local _outvar="$1" + local _dirpath="$2" + local _version_dir="$3" + local _filepath _line _cfg_items _attr_type_gvbvd _value_gvbvd + local _version_pairs _version_pair _version_pair_arr _version_gvbvd _version_dir_gvbvd + + eval "${_outvar}=\"\"" + + get_version_cfg_path "_filepath" "${_dirpath}" + if [ ! -f "${_filepath}" ]; then + return 1 + fi + + check_cfg_version "${_filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + while read _line; do + parse_cfg_line "_cfg_items" "${_line}" + [ "${_cfg_items}" = "" ] && continue + + __index_list_by_cut "${_cfg_items}" 1 "_attr_type_gvbvd" 2 "_value_gvbvd" + + if [ "${_attr_type_gvbvd}" = "installed" ]; then + unpack_versions "_version_pairs" "${_value_gvbvd}" + for _version_pair in ${_version_pairs}; do + unpack_version_pair "_version_pair_arr" "${_version_pair}" + __index_list_by_cut "${_version_pair_arr}" 0 "_version_gvbvd" 1 "_version_dir_gvbvd" + if [ "${_version_dir_gvbvd}" = "${_version_dir}" ]; then + eval "${_outvar}=\"${_version_gvbvd}\"" + return 0 + fi + done + fi + done < "${_filepath}" + + return 1 +} + +# 根据版本号与版本目录获取所有安装包 +get_installed_packages_by_version_version_dir() { + local _outvar="$1" + local _dirpath="$2" + local _version="$3" + local _version_dir="$4" + local _filepath _line _cfg_items + local _package_gipbvvd _attr_type_gipbvvd _value_gipbvvd _version_pairs _in_list + local _packages_gipbvvd="" + + eval "${_outvar}=\"\"" + + get_version_cfg_path "_filepath" "${_dirpath}" + if [ ! -f "${_filepath}" ]; then + return 1 + fi + + check_cfg_version "${_filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + while read _line; do + parse_cfg_line "_cfg_items" "${_line}" + [ "${_cfg_items}" = "" ] && continue + + __index_list_by_cut "${_cfg_items}" 0 "_package_gipbvvd" 1 "_attr_type_gipbvvd" 2 "_value_gipbvvd" + + if [ "${_attr_type_gipbvvd}" = "installed" ]; then + unpack_versions "_version_pairs" "${_value_gipbvvd}" + __item_in_list "_in_list" "${_version}:${_version_dir}" ${_version_pairs} + if [ "${_in_list}" = "true" ]; then + if [ "${_packages_gipbvvd}" = "" ]; then + _packages_gipbvvd="${_package_gipbvvd}" + else + _packages_gipbvvd="${_packages_gipbvvd} ${_package_gipbvvd}" + fi + fi + fi + done < "${_filepath}" + + eval "${_outvar}=\"${_packages_gipbvvd}\"" +} + +# 获取所有安装包 +get_installed_packages() { + local _outvar="$1" + local _dirpath="$2" + local _filepath _line _cfg_items _package_name_gip _attr_type_gip _packages="" + + eval "${_outvar}=\"\"" + + get_version_cfg_path "_filepath" "${_dirpath}" + + if [ ! -f "${_filepath}" ]; then + return 0 + fi + + check_cfg_version "${_filepath}" + if [ $? -ne 0 ]; then + return 1 + fi + + while read _line; do + parse_cfg_line "_cfg_items" "${_line}" + [ "${_cfg_items}" = "" ] && continue + + __index_list_by_cut "${_cfg_items}" 0 "_package_name_gip" 1 "_attr_type_gip" + + if [ "${_attr_type_gip}" = "installed" ]; then + if [ "${_packages}" = "" ]; then + _packages="${_package_name_gip}" + else + _packages="${_packages} ${_package_name_gip}" + fi + fi + done < "${_filepath}" + + eval "${_outvar}=\"${_packages}\"" +} + +# version.cfg文件是否存在 +# 返回值0为真,1为假 +version_cfg_exists() { + local dirpath="$1" + local filepath + + get_version_cfg_path "filepath" "$dirpath" + if [ -f "$filepath" ]; then + return 0 + fi + return 1 +} + +# 显示version.cfg文件 +show_version_cfg() { + local dirpath="$1" + local filepath + + get_version_cfg_path "filepath" "$dirpath" + if [ -f "$filepath" ]; then + cat "$filepath" + fi +} diff --git a/scripts/package/common/sh/version_compatiable.inc b/scripts/package/common/sh/version_compatiable.inc new file mode 100644 index 0000000000000000000000000000000000000000..57054a6eebd8e58cf574107e893d81d1473c4d52 --- /dev/null +++ b/scripts/package/common/sh/version_compatiable.inc @@ -0,0 +1,197 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +# 创建列表 +_make_list() { + local _outvar="$1" + eval "${_outvar}=\"\"" +} + +# 列表添加元素 +_append_list() { + local _outvar="$1" + local _item="$2" + + local _value + eval "_value=\"\${${_outvar}}\"" + + if [ "${_value}" = "" ]; then + _value="${_item}" + else + _value="${_value} ${_item}" + fi + + eval "${_outvar}=\"${_value}\"" +} + +# 获取需求包列表。 +_get_required_packages() { + local _outvar="$1" + local _version_info_path="$2" + local _packages + + if [ ! -f "${_version_info_path}" ]; then + eval "${_outvar}=\"\"" + return 1 + fi + + _packages=$(awk ' + function join(items, len, sep, result, i) { + if (len >= 1) { + result = items[1] + for (i = 2; i <= len; i++) { + result = sprintf("%s%s%s", result, sep, items[i]) + } + return result + } + return "" + } + + BEGIN { + len_packages = 0 + } + /^required_package_.+_version=/ { + split($0, line_tokens, "=") + len_require_tokens = split(line_tokens[1], require_tokens, "_") + len_package_names = 0 + for (i = 3; i < len_require_tokens; i++) { + len_package_names++ + package_names[len_package_names] = require_tokens[i] + } + package_name = join(package_names, len_package_names, "_") + + len_packages += 1 + packages[len_packages] = package_name + } + END { + if (len_packages >= 1) { + printf("%s", packages[1]) + for (i = 2; i <= len_packages; i++) { + printf(" %s", packages[i]) + } + } + } + ' "${_version_info_path}") + eval "${_outvar}=\"${_packages}\"" +} + +# 获取需求包信息。 +_get_required_package_info() { + local _outvar="$1" + local _version_info_path="$2" + local _pkg_name="$3" + local _required_pkg_name + local _required_value + + if [ ! -f "${_version_info_path}" ]; then + eval "${_outvar}=\"\"" + return 1 + fi + + _required_pkg_name="required_package_${_pkg_name}_version" + _required_value="$(grep "^${_required_pkg_name}=" "${_version_info_path}" | cut -d= -f2-)" + # _required_value取得的值带有双引号,eval时不可以在外侧再添加双引号 + + eval "${_outvar}=${_required_value}" +} + +# 检查版本与需求版本兼容性。 +# 兼容返回0,不兼容返回1 +_check_version_required() { + local version="$1" + local require="$2" + local script_dir="$3" + local result + + result=$(awk -f "${script_dir}/check_version_required.awk" -v version="${version}" -v all_required="${require}") + if [ "${result}" = "T" ]; then + return 0 + fi + + return 1 +} + +# 检查包版本兼容性。 +_check_package_version_compatiable() { + local version_info_path="$1" + local pkg_version_info_path="$2" + local package="$3" + local script_dir="$4" + + local pkg_version + local required + + # get pkg_version + get_package_version "pkg_version" "${pkg_version_info_path}" + # get required + _get_required_package_info "required" "${version_info_path}" "${package}" + # check pkg_version and required + _check_version_required "${pkg_version}" "${required}" "${script_dir}" + if [ $? -eq 0 ]; then + comm_log "INFO" "${package} is installed, current version: ${pkg_version}, version check successfully." + return 0 + fi + + comm_log "ERROR" "${package} is installed, current version: ${pkg_version}, required version is ${required}, version check failed." + return 1 +} + + +# 检查版本兼容性。 +_check_version_compatiable() { + local version_info_path="$1" + local install_path="$2" + local script_dir="$3" + + local check_result=0 + local failed_list + local required_packages + local package + local self_version + local pkg_version_info_path + local pkg_installed + local driver_install_path + + _get_required_packages "required_packages" "${version_info_path}" + get_package_version "self_version" "${version_info_path}" + + _make_list "failed_list" + + for package in ${required_packages}; do + if [ "${package}" = "driver" ]; then + get_driver_install_path "driver_install_path" "${install_path}" + if [ "${driver_install_path}" != "" ]; then + pkg_installed="true" + else + pkg_installed="false" + fi + pkg_version_info_path="${driver_install_path}/${package}/version.info" + else + does_pkg_installed "${install_path}" "${package}" "pkg_installed" + pkg_version_info_path="${install_path}/${package}/version.info" + fi + if [ "${pkg_installed}" = "true" ] && [ -f "${pkg_version_info_path}" ]; then + _check_package_version_compatiable "${version_info_path}" "${pkg_version_info_path}" "${package}" "${script_dir}" + if [ $? -ne 0 ]; then + check_result=1 + _append_list "failed_list" "${package}" + fi + else + comm_log "INFO" "${package} is not installed, does not need to check." + fi + done + + if [ ${check_result} -ne 0 ]; then + comm_log "ERROR" "version check failed, please uninstall incompatible packages or install compatible packages. [$(echo ${failed_list} | sed 's/ /, /g')]" + fi + + return ${check_result} +} \ No newline at end of file diff --git a/scripts/package/latest_manager/scripts/filelist.csv b/scripts/package/latest_manager/scripts/filelist.csv new file mode 100644 index 0000000000000000000000000000000000000000..185dcf268613530d9dc056adb56184b0f95228d2 --- /dev/null +++ b/scripts/package/latest_manager/scripts/filelist.csv @@ -0,0 +1,16 @@ +module,operation,relative_path_in_pkg,relative_install_path,is_in_docker,permission,owner:group,install_type,softlink,feature,is_common_path,configurable,hash,block,pkg_inner_softlink,chip +NA,mkdir,NA,manager,TRUE,550,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/filelist.csv,manager/filelist.csv,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/install.sh,manager/install.sh,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/manager.sh,manager.sh,TRUE,550,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/manager_func.sh,manager/manager_func.sh,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/script_operator.inc,manager/script_operator.inc,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/uninstall.sh,manager/uninstall.sh,TRUE,550,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/version.info,manager/version.info,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/version_compatiable.inc,manager/version_compatiable.inc,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/check_version_required.awk,manager/check_version_required.awk,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/common_func_v2.inc,manager/common_func_v2.inc,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/common_func.inc,manager/common_func.inc,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/common_installer.inc,manager/common_installer.inc,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/install_common_parser.sh,manager/install_common_parser.sh,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all +NA,copy,latest_manager/version_cfg.inc,manager/version_cfg.inc,TRUE,440,\\$username:\\$usergroup,all,NA,all,N,FALSE,NA,latest_manager,NA,all diff --git a/scripts/package/latest_manager/scripts/install.sh b/scripts/package/latest_manager/scripts/install.sh new file mode 100644 index 0000000000000000000000000000000000000000..0d8fbc867e85fc96ac5a5e7419032d9e71704e52 --- /dev/null +++ b/scripts/package/latest_manager/scripts/install.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +CURPATH=$(dirname $(readlink -f "$0")) +USERNAME=$(id -un) +USERGROUP=$(id -gn) +common_func_path="${CURPATH}/common_func.inc" + +. "$common_func_path" + +INSTALL_PATH="" +IS_UPGRADE="n" + +set_comm_log "Latest_manager" "$COMM_LOGFILE" + +while true +do + case "$1" in + --install-path=*) + INSTALL_PATH="$(echo "$1" | cut -d"=" -f2-)" + shift + ;; + --upgrade) + IS_UPGRADE="y" + shift + ;; + -*) + comm_log "ERROR" "Unsupported parameters : $1" + exit 1 + ;; + *) + break + ;; + esac +done + +if [ "$INSTALL_PATH" = "" ]; then + comm_log "ERROR" "--install-path parameter is required!" + exit 1 +fi + +if ! sh "$CURPATH/install_common_parser.sh" --package="latest_manager" --install --username="$USERNAME" --usergroup="$USERGROUP" \ + --simple-install "full" "$INSTALL_PATH" "$CURPATH/filelist.csv" "all"; then + comm_log "ERROR" "install failed!" + exit 1 +fi + +if [ "$IS_UPGRADE" = "y" ] && ! "$INSTALL_PATH/manager.sh" "migrate_latest_data"; then + comm_log "ERROR" "migrate latest data failed!" + exit 1 +fi diff --git a/scripts/package/latest_manager/scripts/manager.sh b/scripts/package/latest_manager/scripts/manager.sh new file mode 100644 index 0000000000000000000000000000000000000000..794d85e02a0118dc458bcf260ac679228fe9f6d1 --- /dev/null +++ b/scripts/package/latest_manager/scripts/manager.sh @@ -0,0 +1,124 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +CURPATH=$(dirname "$(readlink -f "$0")") +VAR_PATH="$CURPATH" +common_func_path="$CURPATH/manager/common_func.inc" +version_compatiable_path="$CURPATH/manager/version_compatiable.inc" +common_func_v2_path="$CURPATH/manager/common_func_v2.inc" +version_cfg_path="$CURPATH/manager/version_cfg.inc" +script_operator_path="$CURPATH/manager/script_operator.inc" +manager_func_path="$CURPATH/manager/manager_func.sh" + +. "$common_func_path" +. "$version_compatiable_path" +. "$common_func_v2_path" +. "$version_cfg_path" +. "$script_operator_path" +. "$manager_func_path" + +set_comm_log "Latest_manager" "$COMM_LOGFILE" + +VERSION="" +VERSION_DIR="" +PACKAGE="" +DOCKER_ROOT="" +INTPUT_INSTALL_FOR_ALL="n" +IS_RECREATE_SOFTLINK="n" +INCREMENT="n" + +while true +do + case "$1" in + --version) + VERSION="$2" + shift 2 + ;; + --version-dir) + VERSION_DIR="$2" + shift 2 + ;; + --package) + PACKAGE="$2" + shift 2 + ;; + --package-dir) + shift 2 + ;; + --serial) + shift 2 + ;; + --install-type) + shift 2 + ;; + --feature) + shift 2 + ;; + --chip) + shift 2 + ;; + --filelist) + shift 2 + ;; + --docker-root) + DOCKER_ROOT="$2" + shift 2 + ;; + --recreate-softlink) + IS_RECREATE_SOFTLINK="y" + shift 1 + ;; + --install-for-all) + INTPUT_INSTALL_FOR_ALL="y" + shift 1 + ;; + --increment) + INCREMENT="y" + shift 1 + ;; + -*) + comm_log "ERROR" "Unsupported parameters : $1" + exit 1 + ;; + *) + break + ;; + esac +done + +if [ "$PACKAGE" != "" ]; then + get_titled_package_name "TITLED_PACKAGE" "$PACKAGE" + set_comm_log "$TITLED_PACKAGE" "$COMM_LOGFILE" +fi + +OPERATION="$1" + +if [ "$OPERATION" = "package_installed" ]; then + package_installed "$CURPATH" "$VERSION" "$VERSION_DIR" "$PACKAGE" \ + "$INTPUT_INSTALL_FOR_ALL" "$DOCKER_ROOT" +elif [ "$OPERATION" = "package_pre_uninstall" ]; then + package_pre_uninstall "$CURPATH" "$VERSION" "$VERSION_DIR" "$PACKAGE" \ + "$INTPUT_INSTALL_FOR_ALL" "$DOCKER_ROOT" +elif [ "$OPERATION" = "package_uninstalled" ]; then + package_uninstalled "$CURPATH" "$VERSION" "$VERSION_DIR" "$PACKAGE" "$IS_RECREATE_SOFTLINK" \ + "$DOCKER_ROOT" +elif [ "$OPERATION" = "package_create_softlink" ]; then + package_create_softlink "$CURPATH" "$VERSION" "$VERSION_DIR" "$PACKAGE" "$DOCKER_ROOT" +elif [ "$OPERATION" = "package_remove_softlink" ]; then + package_remove_softlink "$CURPATH" "$VERSION" "$VERSION_DIR" "$PACKAGE" "$DOCKER_ROOT" +elif [ "$OPERATION" = "create_version_softlink" ]; then + create_version_softlink "$CURPATH" "$VERSION_DIR" +elif [ "$OPERATION" = "remove_latest_softlink" ]; then + remove_latest_softlink "$CURPATH" +elif [ "$OPERATION" = "migrate_latest_data" ]; then + migrate_latest_data "$CURPATH" +fi diff --git a/scripts/package/latest_manager/scripts/manager_func.sh b/scripts/package/latest_manager/scripts/manager_func.sh new file mode 100644 index 0000000000000000000000000000000000000000..b1687aed6f87611d0bc1ab7c11ba513de0a00c8d --- /dev/null +++ b/scripts/package/latest_manager/scripts/manager_func.sh @@ -0,0 +1,1725 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +USERNAME="$(id -un)" +USERGROUP="$(id -gn)" + +CREATE_VERSION_SOFTLINK="create_version_softlink.sh" +REMOVE_LATEST_SOFTLINK="remove_latest_softlink.sh" + +MANAGER_INFO="$VAR_PATH/manager.info" + +# 获取manager引用计数 +get_manager_refs() { + local _outvar="$1" + local _var_path="$2" + local _result + + if [ -f "$_var_path/manager_refs" ]; then + _result="$(cat "$_var_path/manager_refs")" + if [ "$_result" = "" ]; then + _result="0" + fi + else + _result="0" + fi + eval "${_outvar}=\"${_result}\"" +} + +# manager引用计数是否存在 +# 返回值0为真,1为假 +manager_refs_exists() { + local var_path="$1" + + if [ -f "$var_path/manager_refs" ]; then + return 0 + fi + return 1 +} + +# 删除manager引用计数 +remove_manager_refs() { + local var_path="$1" + rm -f "$var_path/manager_refs" +} + +# 增加manager引用计数 +inc_manager_refs() { + local var_path="$1" + if [ -f "$var_path/manager_refs" ]; then + xargs expr 1 + < "$var_path/manager_refs" | (read -r arg; echo "$arg" > "$var_path/manager_refs") + else + echo "1" > "$var_path/manager_refs" + fi +} + +# 减少manager引用计数 +dec_manager_refs() { + local var_path="$1" + local cnt + + if [ -f "$var_path/manager_refs" ]; then + xargs expr -1 + < "$var_path/manager_refs" | (read -r arg; echo "$arg" > "$var_path/manager_refs") + + get_manager_refs cnt "$var_path" + if [ "$cnt" -le 0 ]; then + rm -f "$var_path/manager_refs" + fi + fi +} + +# 获取是否需要install_for_all +get_install_for_all() { + local _outvar="$1" + local _result + + if [ ! -f "$MANAGER_INFO" ]; then + eval "${_outvar}=\"n\"" + return 0 + fi + + _result="$(grep "^install_for_all=" "$MANAGER_INFO" | cut -d= -f2-)" + if [ "$_result" = "" ]; then + eval "${_outvar}=\"n\"" + return 0 + fi + + eval "${_outvar}=\"${_result}\"" +} + +# 过滤配置文件参数 +filter_info_param() { + local name="$1" + local value="$2" + + awk -v name="$name" -v value="$value" -F= ' + BEGIN { + MATCHED = 0 + OFS = "=" + } + $1 == name { + MATCHED = 1 + print $1, value + } + $1 != name { + print $0 + } + END { + if (MATCHED == 0) { + print name, value + } + } + ' +} + +# 修改配置文件参数 +modify_info_param() { + local filepath="$1" + local name="$2" + local value="$3" + local content + + if [ ! -f "$filepath" ]; then + return 1 + fi + + content="$(cat "$filepath" | filter_info_param "$name" "$value")" + with_chmod "$filepath" "700" write_text "$content" "$filepath" +} + +# 包创建软链事件 +package_create_softlink() { + local var_path="$1" + local version="$2" + local version_dir="$3" + local package="$4" + local docker_root="$5" + local ret install_path pkg_running_version install_for_all + + install_path="$(dirname "$(dirname "$var_path")")" + + get_running_package_version "pkg_running_version" "$install_path/$LATEST_DIR" "$package" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "$pkg_running_version" != "" ]; then + unpack_version_pair "version_pair_arr" "$pkg_running_version" + __index_list "$version_pair_arr" 0 "last_version" 1 "last_version_dir" + compat_del_package_softlink_in_latest "$install_path" "$package" "$last_version" "$last_version_dir" \ + "$LATEST_DIR" "$USERNAME" "$docker_root" + check_ret_error "$?" "delete $package softlink in latest failed in package create softlink!" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + get_install_for_all "install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + INSTALL_FOR_ALL="$install_for_all" + + # 版本兼容性检查 + check_compatiable_in_multi_version_install "$install_path" "$USERNAME" "" \ + "$version" "$version_dir" "$package" + ret="$?" && [ $ret -ne 0 ] && return $ret + + do_create_package_softlink_to_latest "$install_path" "$package" "$version" "$version_dir" "$LATEST_DIR" \ + "$USERNAME" "$USERGROUP" "$install_for_all" "$docker_root" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 包安装事件 +package_installed() { + local var_path="$1" + local version="$2" + local version_dir="$3" + local package="$4" + local install_for_all="$5" + local docker_root="$6" + local ret install_path pkg_running_version version_pair_arr last_version last_version_dir + local config_install_for_all + + if [ "$INCREMENT" != "y" ]; then + inc_manager_refs "$var_path" + fi + install_path="$(dirname "$(dirname "$var_path")")" + + create_total_create_softlink_script "$var_path/manager" "$install_path" "$version_dir" "$USERNAME" "$USERGROUP" + check_ret_warning "$?" "$package create total create softlink script in $version_dir in failed!" + + create_total_remove_softlink_script "$var_path/manager" "$install_path" "$LATEST_DIR" "$USERNAME" "$USERGROUP" + check_ret_warning "$?" "Create total remove softlink script in $LATEST_DIR in package installed failed!" + + create_platform_ini "$install_path" "$LATEST_DIR" "$USERNAME" "$USERGROUP" + check_ret_warning "$?" "Create platform.ini in $LATEST_DIR in package installed failed!" + + get_install_for_all "config_install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "$install_for_all" != "$config_install_for_all" ]; then + ensure_file "$MANAGER_INFO" "440" "$USERNAME" "$USERGROUP" "$install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + + modify_info_param "$MANAGER_INFO" "install_for_all" "$install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + package_create_softlink "$var_path" "$version" "$version_dir" "$package" "$docker_root" + ret="$?" && [ $ret -ne 0 ] && return $ret + + add_installed_package_version "$install_path/$LATEST_DIR" "$package" "$version" "$version_dir" + check_ret_error "$?" "Add $package installed version $version $version_dir in multi version install failed!" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 包删除软链事件 +package_remove_softlink() { + local var_path="$1" + local version="$2" + local version_dir="$3" + local package="$4" + local docker_root="$5" + local ret install_path is_running install_for_all + + install_path="$(dirname "$(dirname "$var_path")")" + + # version参数可能为空 + # 1. 新版本升级老版本场景,断开兼容性软链时,会使用老版本的install_common_parser.sh, + # 调用新版本的--remove-package-latest-softlink,但不会传version参数。 + # 2. 新版本先装,老版本后装的场景,latest目录下remove_latest_softlink.sh为老版本, + # 调用remove_latest_softlink.sh时,不会传version参数。 + if [ "$version" = "" ]; then + get_version_by_version_dir "version" "$install_path/$LATEST_DIR" "$version_dir" + fi + + get_install_for_all "install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + INSTALL_FOR_ALL="$install_for_all" + + is_package_version_running "is_running" "$install_path/$LATEST_DIR" "$package" "$version" "$version_dir" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "$is_running" = "true" ]; then + do_del_package_softlink_in_latest "$install_path" "$package" "$version" "$version_dir" "$LATEST_DIR" \ + "$USERNAME" "$docker_root" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# 包卸载前事件 +package_pre_uninstall() { + return 0 +} + +# 包卸载事件 +package_uninstalled() { + local var_path="$1" + local version="$2" + local version_dir="$3" + local package="$4" + local is_recreate_softlink="$5" + local docker_root="$6" + local install_path is_upgrade running_packages + + install_path="$(dirname "$(dirname "$var_path")")" + + if ! is_package_version_upgrade "is_upgrade" "$install_path/$LATEST_DIR" "$package" "$version" "$version_dir"; then + return 1 + fi + if [ "$is_upgrade" = "true" ]; then + # 移除version.cfg中的upgrade配置 + if ! unset_upgrade_package "$install_path/$LATEST_DIR" "$package"; then + comm_log "ERROR" "Unset $package upgrade version in package uninstalled failed!" + return 1 + fi + fi + + if ! del_installed_package_version "$install_path/$LATEST_DIR" "$package" "$version" "$version_dir"; then + comm_log "ERROR" "Del $package installed version $version $version_dir in package uninstalled failed!" + return 1 + fi + + # 删除版本目录下创建软链总脚本 + if ! del_total_create_softlink_script "$install_path" "$LATEST_DIR" "$version" "$version_dir"; then + comm_log "WARNING" "Del total create softlink script in $version_dir in package uninstalled failed!" + fi + + if ! version_cfg_exists "$install_path/$LATEST_DIR"; then + # 删除latest目录下删除软链总脚本 + del_total_remove_softlink_script "$install_path" "$LATEST_DIR" + check_ret_warning "$?" "Del total remove softlink script in $LATEST_DIR in package uninstalled failed!" + + # 删除latest目录下platform.ini + del_platform_ini "$install_path" "$LATEST_DIR" + check_ret_warning "$?" "Del platform.ini in $LATEST_DIR in package uninstalled failed!" + fi + + if [ "$is_recreate_softlink" = "y" ]; then + # 多版本卸载时检查版本兼容性 + if ! recreate_compatiable_softlink_in_multi_version_uninstall "$install_path" "$LATEST_DIR" "$package" \ + "$USERNAME" "$USERGROUP" "$docker_root"; then + comm_log "ERROR" "Recreate ${package} compatiable softlink in package uninstalled failed!" + return 1 + fi + fi + + dec_manager_refs "$var_path" + if ! manager_refs_exists "$var_path"; then + rm -f "$MANAGER_INFO" + sh "$var_path/manager/uninstall.sh" + fi + return 0 +} + +# 设置版本软链接 +create_version_softlink() { + local var_path="$1" + local version_dir="$2" + local install_path + local total_ret="0" version packages package version_pair version_pair_arr + local ret del_version del_version_dir install_for_all + + install_path="$(dirname "$(dirname "$var_path")")" + + get_version_by_version_dir "version" "$install_path/$LATEST_DIR" "$version_dir" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_installed_packages_by_version_version_dir "packages" "$install_path/$LATEST_DIR" "$version" "$version_dir" + if [ "$packages" = "" ]; then + return 1 + fi + + get_install_for_all "install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + INSTALL_FOR_ALL="$install_for_all" + + for package in ${packages}; do + if ! get_running_package_version "version_pair" "$install_path/$LATEST_DIR" "$package"; then + total_ret=1 + continue + fi + + if [ "$version_pair" != "" ]; then + unpack_version_pair "version_pair_arr" "$version_pair" + __index_list "$version_pair_arr" 0 "del_version" 1 "del_version_dir" + + if ! do_del_package_softlink_in_latest "$install_path" "$package" "$del_version" "$del_version_dir" "$LATEST_DIR" \ + "$USERNAME" ""; then + total_ret=1 + fi + fi + + if ! do_create_package_softlink_to_latest "$install_path" "$package" "$version" "$version_dir" "$LATEST_DIR" \ + "$USERNAME" "$USERGROUP" "$install_for_all" ""; then + total_ret=1 + fi + done + + return $total_ret +} + +# 删除运行软链接 +remove_latest_softlink() { + local var_path="$1" + local install_path + local total_ret="0" ret running_packages package version_pair version_pair_arr version version_dir + local install_for_all + + install_path="$(dirname "$(dirname "$var_path")")" + + get_running_packages "running_packages" "$install_path/$LATEST_DIR" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${running_packages}" = "" ]; then + return 0 + fi + + get_install_for_all "install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + INSTALL_FOR_ALL="$install_for_all" + + for package in ${running_packages}; do + if ! get_running_package_version "version_pair" "$install_path/$LATEST_DIR" "$package"; then + total_ret=1 + continue + fi + + unpack_version_pair "version_pair_arr" "$version_pair" + __index_list "$version_pair_arr" 0 "version" 1 "version_dir" + + if ! do_del_package_softlink_in_latest "$install_path" "$package" "$version" "$version_dir" "$LATEST_DIR" \ + "$USERNAME" ""; then + total_ret=1 + fi + done + + return $total_ret +} + +# 创建子包软链到latest目录下 +do_create_package_softlink_to_latest() { + local install_path="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local latest_dir="$5" + local username="$6" + local usergroup="$7" + local install_for_all="$8" + local docker_root="$9" + local ret total_ret="0" install_type feature_type feature_param filelist_path install_info_path + local chip_type + + check_param_not_empty "package" "need set package parameter in create package softlink to latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + _package_to_log_pkg_name "LOG_PKG_NAME" "${package}" + check_ret_error "$?" "Set log package name failed in create package softlink to latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + if [ ! -d "${install_path}/${latest_dir}" ]; then + make_dir_with_permission "${install_path}/${latest_dir}" "750" "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + get_package_filelist "filelist_path" "${install_path}" "${version_dir}" "${package}" + get_package_install_info "install_info_path" "${install_path}" "${version_dir}" "${package}" + + check_file_exists "${install_info_path}" "${install_info_path} doesn't exist in create package softlink to latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + get_package_install_type "install_type" "${install_info_path}" "${package}" + check_ret_error "$?" "Get install_type from ascend_install.info failed in create package softlink to latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + get_package_feature_type "feature_type" "${install_info_path}" "${package}" "install" + check_ret_error "$?" "Get feature_type from ascend_install.info failed in create package softlink to latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + get_package_chip_type "chip_type" "${install_info_path}" "${package}" "install" + check_ret_error "$?" "Get chip_type from ascend_install.info failed in create package softlink to latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + pack_feature_param "feature_param" "${feature_type}" "n" "${chip_type}" + + # 创建公共目录到latest目录下的软链接 + create_common_dirs_softlink_to_latest "${install_type}" "${install_path}" "${package}" "${version_dir}" "${latest_dir}" \ + "${filelist_path}" "${feature_param}" "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 创建版本包到latest目录下的软链接 + create_package_dir_softlink_to_latest "${install_path}" "${version_dir}" "${latest_dir}" "${package}" \ + "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # latest目录下公共脚本添加条目 + add_latest_common_script "${install_path}/${latest_dir}" "${package}" "${username}" "${usergroup}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 更新version.cfg中的running配置 + set_running_package_version "${install_path}/${latest_dir}" "${package}" "${version}" "${version_dir}" + check_ret_error "$?" "Set ${package} running version ${version} ${version_dir} in create package softlink to latest failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 更新version.cfg中的upgrade配置 + set_upgrade_package_version "${install_path}/${latest_dir}" "${package}" "${version}" "${version_dir}" + check_ret_error "$?" "Set ${package} upgrade version ${version} ${version_dir} in create package softlink to latest failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return ${total_ret} +} + + +# [兼容老版本]创建子包软链到latest目录下 +compat_create_package_softlink_to_latest() { + local install_path="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local latest_dir="$5" + local username="$6" + local usergroup="$7" + local install_for_all="$8" + local docker_root="$9" + local ret installer_path + + get_package_install_common_parser "installer_path" "${install_path}" "${version_dir}" "${package}" + check_file_exists "${installer_path}" "${installer_path} doesn't exist in create package softlink to latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + install_options="--create-latest-softlink" + install_options="${install_options} --install-path=\"${install_path}\" --package=\"${package}\" --version=\"${version}\" --version-dir=\"${version_dir}\"" + install_options="${install_options} --latest-dir=\"${latest_dir}\" --username=\"${username}\" --usergroup=\"${usergroup}\"" + if [ "${install_for_all}" = "y" ]; then + install_options="${install_options} --install_for_all" + fi + if [ "${docker_root}" != "" ]; then + install_options="${install_options} --docker-root=\"${docker_root}\"" + fi + + eval sh "${installer_path}" "${install_options}" + check_ret_error "$?" "Create ${version_dir} ${package} softlink to latest failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 删除latest目录下子包的软链接 +do_del_package_softlink_in_latest() { + local install_path="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local latest_dir="$5" + local username="$6" + local docker_root="$7" + local ret install_type feature_type feature_param package_dirpath filelist_path install_info_path + local chip_type + + _package_to_log_pkg_name "LOG_PKG_NAME" "${package}" + check_ret_error "$?" "Set log package name failed in del package softlink in latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + if [ ! -d "${install_path}/${latest_dir}" ]; then + comm_log "ERROR" "${install_path}/${latest_dir} doesn't exist in del package softlink in latest!" + return 1 + fi + + get_package_dirpath "package_dirpath" "$package" + filelist_path="$install_path/$version_dir/$package_dirpath/script/filelist.csv" + install_info_path="$install_path/$version_dir/$package_dirpath/ascend_install.info" + + check_file_exists "${install_info_path}" "${install_info_path} doesn't exist in del package softlink in latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 卸载时install_type强制为full + install_type="full" + + get_package_feature_type "feature_type" "${install_info_path}" "${package}" "uninstall" + check_ret_error "$?" "Get feature_type from ascend_install.info failed in del package softlink in latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + get_package_chip_type "chip_type" "${install_info_path}" "${package}" "uninstall" + check_ret_error "$?" "Get chip_type from ascend_install.info failed in del package softlink to latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + pack_feature_param "feature_param" "${feature_type}" "n" "${chip_type}" + + # latest目录下公共脚本删除条目 + del_latest_common_script "${install_path}/${latest_dir}" "${package}" "${username}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 删除公共目录到latest目录下的软链接 + del_common_dirs_softlink_from_latest "${install_type}" "${install_path}" "${package}" "${version_dir}" "${latest_dir}" \ + "${filelist_path}" "${feature_param}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 删除版本包到latest目录下的软链接 + del_package_dir_softlink_in_latest "${install_path}" "${latest_dir}" "${package}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 删除latest下tools空目录。toolkit包创建latest软链时,latest下存在软链tools/simulator -> ${arch}-linux/simulator + # 通过filelist.csv文件,无法删除tools目录 + # 解决toolkit包安装卸载latest目录下残留tools目录问题 + remove_dir_if_empty "${install_path}/${latest_dir}/tools" + + # 移除version.cfg中的running配置 + unset_running_package "${install_path}/${latest_dir}" "${package}" + check_ret_error "$?" "Unset ${package} running version in del package softlink in latest failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# [兼容老版本]删除latest目录下子包的软链接 +compat_del_package_softlink_in_latest() { + local install_path="$1" + local package="$2" + local version="$3" + local version_dir="$4" + local latest_dir="$5" + local username="$6" + local docker_root="$7" + local ret installer_path + + get_package_install_common_parser "installer_path" "${install_path}" "${version_dir}" "${package}" + + check_file_exists "${installer_path}" "${installer_path} doesn't exist in del package softlink in latest!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 更新version.cfg中的upgrade配置 + set_upgrade_package_version "${install_path}/${latest_dir}" "${package}" "${version}" "${version_dir}" + check_ret_error "$?" "Set ${package} upgrade version ${version} ${version_dir} in create package softlink to latest failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + install_options="--remove-latest-softlink" + install_options="${install_options} --install-path=\"${install_path}\" --package=\"${package}\" --version-dir=\"${version_dir}\"" + install_options="${install_options} --latest-dir=\"${latest_dir}\" --username=\"${username}\"" + if [ "${docker_root}" != "" ]; then + install_options="${install_options} --docker-root=\"${docker_root}\"" + fi + + eval sh "${installer_path}" "${install_options}" + check_ret_error "$?" "Remove ${version_dir} ${package} softlink in latest failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 获取包安装类型 +get_package_install_type() { + local _outvar="$1" + local _install_info="$2" + local _package="$3" + local _install_type_gpit="" + + eval "${_outvar}=\"\"" + + if [ ! -f "${_install_info}" ]; then + return 1 + fi + + _install_type_gpit="$(grep -i "^\(${_package}_\)\?install_type=" "${_install_info}" | cut -d"=" -f2-)" + if [ "${_install_type_gpit}" = "" ]; then + return 1 + fi + + eval "${_outvar}=\"${_install_type_gpit}\"" +} + +# 获取包特性参数 +get_package_feature_type() { + local _outvar="$1" + local _install_info="$2" + local _package="$3" + local _operation="$4" + local _feature_type_gpft="" + + eval "${_outvar}=\"\"" + + if [ ! -f "${_install_info}" ]; then + return 1 + fi + + if [ "${_package}" = "opp" ]; then + _feature_type_gpft="$(grep -i "^Opp_Install_Feature=" "${_install_info}" | cut -d"=" -f2-)" + else + _feature_type_gpft="$(grep -i "^\(${_package}_\)\?feature_type=" "${_install_info}" | cut -d"=" -f2-)" + fi + if [ "${_feature_type_gpft}" = "" ]; then + _feature_type_gpft="all" + fi + + normalize_feature "_feature_type_gpft" "${_feature_type_gpft}" "${_operation}" + + eval "${_outvar}=\"${_feature_type_gpft}\"" +} + +# 获取包芯片参数 +get_package_chip_type() { + local _outvar="$1" + local _install_info="$2" + local _package="$3" + local _operation="$4" + local _cihp_gpct="" + + eval "${_outvar}=\"\"" + + if [ ! -f "${_install_info}" ]; then + return 1 + fi + + if [ "${_package}" = "opp" ]; then + _cihp_gpct="$(grep -i "^Opp_Install_Chip=" "${_install_info}" | cut -d"=" -f2-)" + else + _cihp_gpct="$(grep -i "^\(${_package}_\)\?chip_type=" "${_install_info}" | cut -d"=" -f2-)" + fi + if [ "${_cihp_gpct}" = "" ]; then + _cihp_gpct="all" + fi + + normalize_feature "_cihp_gpct" "${_cihp_gpct}" "${_operation}" + + eval "${_outvar}=\"${_cihp_gpct}\"" +} + +# 创建latest软链接 +create_latest_softlink() { + local latest_dirpath="$1" + local line="$2" + local version_dirpath="$4" + local target latest_filepath version_filepath softlink + local ret + + __index_list "${line}" 1 "target" 4 "softlink" + + __set_abs_path "${latest_dirpath}" "${target}" "latest_filepath" + __set_abs_path "${version_dirpath}" "${target}" "version_filepath" + + if [ ! -e "$version_filepath" ]; then + # 如果源路径不存在,则跳过软链创建 + return 0 + fi + + if [ -d "${latest_filepath}" ]; then + remove_dir_icp "${latest_filepath}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + create_softlink_icp "-r" "${version_filepath}" "${latest_filepath}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${softlink}" != "NA" ]; then + create_softlink_by_install_path "${latest_dirpath}" "${target}" "${softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + + return 0 +} + +# 删除latest软链接 +del_latest_softlink() { + local latest_dirpath="$1" + local line="$2" + local target latest_filepath softlink + local ret + + __index_list "${line}" 1 "target" 4 "softlink" + + __set_abs_path "${latest_dirpath}" "${target}" "latest_filepath" + + if [ "${softlink}" != "NA" ]; then + remove_softlinks "${install_path}" "${softlink}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + + remove_softlink_icp "${latest_filepath}" "NA" + ret="$?" && [ $ret -ne 0 ] && return $ret + return 0 +} + +# 迁移latest/conf实体目录下的文件到版本conf目录下 +migrate_conf_files_from_latest_to_version() { + local install_type="$1" + local install_path="$2" + local version_dir="$3" + local latest_dir="$4" + local filelist_path="$5" + local feature_param="$6" + local latest_conf_path="${install_path}/${latest_dir}/conf" + local version_conf_path="${install_path}/${version_dir}/conf" + local ret + + if [ -d "${latest_conf_path}" ] && [ ! -L "${latest_conf_path}" ] && [ -d "${version_conf_path}" ]; then + foreach_filelist "filter_common_dirs" "reset_mod_dirs" "${install_type}" "${install_path}/${version_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "no" "normal" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + is_dir_empty "${latest_conf_path}" + # 如果目录不为空,则迁移数据 + if [ $? -ne 0 ]; then + mv -f "${latest_conf_path}"/* "${version_conf_path}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + + remove_dir_icp "${latest_conf_path}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + foreach_filelist "filter_common_dirs" "change_mod_and_own_dirs" "${install_type}" "${install_path}/${version_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "reverse" "normal" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + + return 0 +} + +# 按块创建公共目录软链接到latest目录下 +create_common_dirs_softlink_cross_version() { + local install_path="$1" + local package="$2" + local version_dir="$3" + local latest_dir="$4" + local blocks="$5" + local filelist_path install_info_path install_type feature_type chip_type feature_param + + get_package_filelist "filelist_path" "$install_path" "$version_dir" "$package" + get_package_install_info "install_info_path" "$install_path" "$version_dir" "$package" + + check_file_exists "$install_info_path" "$install_info_path doesn't exist in create common dirs softlink cross version!" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_package_install_type "install_type" "$install_info_path" "$package" + check_ret_error "$?" "Get install_type from ascend_install.info failed in create common dirs softlink cross version!" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_package_feature_type "feature_type" "$install_info_path" "$package" "install" + get_package_chip_type "chip_type" "$install_info_path" "$package" "install" + pack_feature_param "feature_param" "$feature_type" "n" "$chip_type" + + create_common_dirs_softlink_by_blocks "$install_type" "$install_path" "$package" "$version_dir" "$latest_dir" \ + "$filelist_path" "$feature_param" "$blocks" "" + check_ret_error "$?" "Create common dirs softlink by blocks failed in create common dirs softlink cross version!" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 按块创建公共目录软链接到latest目录下 +create_common_dirs_softlink_by_blocks() { + local install_type="$1" + local install_path="$2" + local package="$3" + local version_dir="$4" + local latest_dir="$5" + local filelist_path="$6" + local feature_param="$7" + local blocks="$8" + local custom_create_softlink="$9" + local ret package_dirpath filelist_path + + foreach_filelist_v2 "reset_mod_dirs" "${install_type}" "${install_path}/${latest_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "filter_common_dirs,filter_blocks" "$blocks" "no" "normal" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + foreach_filelist_v2 "create_dirs" "${install_type}" "${install_path}/${latest_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "filter_common_dirs,filter_blocks" "$blocks" "no" "normal" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + foreach_filelist_v2 "create_latest_softlink" "${install_type}" "${install_path}/${latest_dir}" "copy copy_entity move" \ + "${filelist_path}" "${feature_param}" "filter_common_dirs,filter_blocks" "$blocks" "no" "normal" "${install_path}/${version_dir}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 调用脚本创建自定义内容软链接到latest目录下 + if [ "$custom_create_softlink" != "" ] && [ -f "$custom_create_softlink" ]; then + chmod u+x "${custom_create_softlink}" + "${custom_create_softlink}" --install-path="${install_path}" --version-dir="${version_dir}" --latest-dir="${latest_dir}" + check_ret_error "$?" "Run ${package} custom create ${version_dir} softlink failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + + foreach_filelist_v2 "change_mod_and_own_dirs" "${install_type}" "${install_path}/${latest_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "filter_common_dirs,filter_blocks" "$blocks" "reverse" "normal" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 创建公共目录软链接到latest目录下 +create_common_dirs_softlink_to_latest() { + local install_type="$1" + local install_path="$2" + local package="$3" + local version_dir="$4" + local latest_dir="$5" + local filelist_path="$6" + local feature_param="$7" + local username="$8" + local usergroup="$9" + local install_for_all="${10}" + local custom_create_softlink="${install_path}/${version_dir}/${package}/script/${package}_custom_create_softlink.sh" + local db_info_path="$install_path/$latest_dir/var/ascend_package_db.info" + local ret db_info + + migrate_conf_files_from_latest_to_version "${install_type}" "${install_path}" "${version_dir}" "${latest_dir}" \ + "${filelist_path}" "${feature_param}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + ensure_file "$db_info_path" "440" "$username" "$usergroup" "$install_for_all" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + db_info="$( + ( + cat "$db_info_path" + printf "\n" # 防止db.info缺失末尾换行符 + all_common_dirs_blocks_in_filelist "$install_type" "$filelist_path" "$feature_param" \ + | blocks_to_db_item "$package" "$version_dir" + ) | remove_blank_line | sort_1 "|" | fold_2 "|" "" + )" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 注意换行符 + ( + cat "$db_info_path" | remove_blank_line | remain_db_last_item + printf "%s\n" "$db_info" | remove_blank_line | remain_db_last_item + ) | sort_1 | fold_3_keep_2 "" " " | show_diff_3_4 | show_min_nf "4" | select_fields_3_2_1 | sort_1 | fold_3_keep_2 "" " " \ + | ( + total_ret=0 + while read -r tmp_version_dir tmp_package tmp_blocks; do + del_common_dirs_softlink_cross_version "$install_path" "$tmp_package" "$tmp_version_dir" "$latest_dir" \ + "EngineeringCommon $tmp_blocks" + ret="$?" && [ $ret -ne 0 ] && total_ret="1" + done + exit $total_ret + ) + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 安装时总是创建全部块的软链接 + create_common_dirs_softlink_by_blocks "$install_type" "$install_path" "$package" "$version_dir" "$latest_dir" \ + "$filelist_path" "$feature_param" "" "$custom_create_softlink" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + with_chmod "$db_info_path" "700" write_text "$db_info" "$db_info_path" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + + +# 跨版本按块删除公共目录到latest目录下的软链接 +del_common_dirs_softlink_cross_version() { + local install_path="$1" + local package="$2" + local version_dir="$3" + local latest_dir="$4" + local blocks="$5" + local filelist_path install_info_path install_type feature_type chip_type feature_param + + get_package_filelist "filelist_path" "$install_path" "$version_dir" "$package" + get_package_install_info "install_info_path" "$install_path" "$version_dir" "$package" + + check_file_exists "$install_info_path" "$install_info_path doesn't exist in del common dirs softlink cross version!" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_package_install_type "install_type" "$install_info_path" "$package" + check_ret_error "$?" "Get install_type from ascend_install.info failed in del common dirs softlink cross version!" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_package_feature_type "feature_type" "$install_info_path" "$package" "uninstall" + get_package_chip_type "chip_type" "$install_info_path" "$package" "uninstall" + pack_feature_param "feature_param" "$feature_type" "n" "$chip_type" + + del_common_dirs_softlink_by_blocks "$install_type" "$install_path" "$package" "$version_dir" "$latest_dir" \ + "$filelist_path" "$feature_param" "$blocks" "" + check_ret_error "$?" "Del common dirs softlink by blocks failed in del common dirs softlink cross version!" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 按块删除公共目录到latest目录下的软链接 +del_common_dirs_softlink_by_blocks() { + local install_type="$1" + local install_path="$2" + local package="$3" + local version_dir="$4" + local latest_dir="$5" + local filelist_path="$6" + local feature_param="$7" + local blocks="$8" + local custom_remove_softlink="$9" + local ret package_dirpath filelist_path + + create_stash_mod "${install_path}/${latest_dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist_v2 "reset_mod_dirs_with_stash_mod" "${install_type}" "${install_path}/${latest_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "filter_common_dirs,filter_blocks" "$blocks" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 调用脚本删除latest目录下自定义内容软链接 + if [ "$custom_remove_softlink" != "" ] && [ -f "$custom_remove_softlink" ]; then + chmod u+x "${custom_remove_softlink}" + "${custom_remove_softlink}" --install-path="${install_path}" --version-dir="${version_dir}" --latest-dir="${latest_dir}" + check_ret_error "$?" "Run ${package} custom remove ${version_dir} softlink failed!" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + + foreach_filelist_v2 "del_latest_softlink" "${install_type}" "${install_path}/${latest_dir}" "copy copy_entity move" \ + "${filelist_path}" "${feature_param}" "filter_common_dirs,filter_blocks" "$blocks" "no" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_filelist_v2 "remove_install_dirs" "${install_type}" "${install_path}/${latest_dir}" "mkdir" \ + "${filelist_path}" "${feature_param}" "filter_common_dirs,filter_blocks" "$blocks" "reverse" "normal" + ret="$?" && [ $ret -ne 0 ] && return $ret + + foreach_stashmod "restore_stash_mod" "${install_path}/${latest_dir}" "reverse" + ret="$?" && [ $ret -ne 0 ] && return $ret + + remove_stash_mod "${install_path}/${latest_dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 删除公共目录到latest目录下的软链接 +del_common_dirs_softlink_from_latest() { + local install_type="$1" + local install_path="$2" + local package="$3" + local version_dir="$4" + local latest_dir="$5" + local filelist_path="$6" + local feature_param="$7" + local custom_remove_softlink="${install_path}/${version_dir}/${package}/script/${package}_custom_remove_softlink.sh" + local db_info_path="$install_path/$latest_dir/var/ascend_package_db.info" + local ret db_info_origin db_info diff_result blocks_to_remove + + if [ -f "$db_info_path" ]; then + db_info_origin="$(cat "$db_info_path")""\n" + else + db_info_origin="" + fi + + db_info="$(printf "$db_info_origin" | del_db_items "$package" "$version_dir")" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 注意换行符和次序 + diff_result="$( + ( + printf "%s\n" "$db_info" | remove_blank_line | remain_db_last_item + printf "$db_info_origin" | remove_blank_line | remain_db_last_item + ) | sort_1 | fold_3_keep_2 "" " " | show_diff_3_4 + )" + blocks_to_remove="$(printf "%s\n" "$diff_result" | select_fields_1 | xargs)" + + # blocks_to_remove可以为空 + del_common_dirs_softlink_by_blocks "$install_type" "$install_path" "$package" "$version_dir" "$latest_dir" \ + "$filelist_path" "$feature_param" "EngineeringCommon $blocks_to_remove" "$custom_remove_softlink" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + printf "%s\n" "$diff_result" | show_min_nf "4" | select_fields_3_2_1 | sort_1 | fold_3_keep_2 "" " " \ + | ( + total_ret=0 + while read -r tmp_version_dir tmp_package tmp_blocks; do + create_common_dirs_softlink_cross_version "$install_path" "$tmp_package" "$tmp_version_dir" "$latest_dir" \ + "EngineeringCommon $tmp_blocks" + ret="$?" && [ $ret -ne 0 ] && total_ret="1" + done + exit $total_ret + ) + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + if [ "$db_info" != "" ]; then + with_chmod "$db_info_path" "700" write_text "$db_info" "$db_info_path" + else + rm -f "$db_info_path" + fi + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# latest目录下公共脚本添加条目 +add_latest_common_script() { + local latest_path="$1" + local package="$2" + local username="$3" + local usergroup="$4" + local docker_root="$5" + local ret mod + + # 保存bin目录的权限 + get_file_mod "mod" "-L" "${latest_path}/bin" + + # 给latest/bin目录提升权限到750 + chmod "750" "${latest_path}/bin" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 设置setenv + add_setenv "${latest_path}" "${package}" "NA" "${username}" "${usergroup}" "true" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 给latest目录添加prereq_check条目 + add_prereq_check "${latest_path}" "${package}" "${username}" "${usergroup}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 恢复bin目录的权限 + chmod "${mod}" "${latest_path}/bin" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# latest目录下公共脚本删除条目 +del_latest_common_script() { + local latest_path="$1" + local package="$2" + local username="$3" + local docker_root="$4" + local ret + + # 保存bin目录的权限 + get_file_mod "mod" "-L" "${latest_path}/bin" + + # 给latest/bin目录提升权限到750 + chmod "750" "${latest_path}/bin" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # unsetenv + del_setenv "${latest_path}" "${package}" "${username}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 给latest目录删除prereq_check条目 + del_prereq_check "${latest_path}" "${package}" "${docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 恢复bin目录的权限 + chmod "${mod}" "${latest_path}/bin" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 文件中添加一个空行 +add_blank_line_to_file() { + local filepath="$1" + + echo >> "${filepath}" +} + +# 总设置软链脚本是否存在 +# 返回值0为真,1为假 +total_create_softlink_script_exists() { + local install_path="$1" + local version_dir="$2" + + if [ -f "$install_path/$version_dir/$CREATE_VERSION_SOFTLINK" ]; then + return 0 + fi + return 1 +} + +# 创建总设置软链脚本 +create_total_create_softlink_script() { + local script_dir="$1" + local install_path="$2" + local version_dir="$3" + local username="$4" + local usergroup="$5" + local script_filepath="$install_path/$version_dir/$CREATE_VERSION_SOFTLINK" + local ret + + rm -f "$script_filepath" + cat "$script_dir/common_installer.inc" > "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + add_blank_line_to_file "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + sed -n '/^## module log/,/^## end module/ p' "$script_dir/common_func.inc" >> "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + add_blank_line_to_file "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "LATEST_DIR=\"$LATEST_DIR\"" >> "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + add_blank_line_to_file "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "notify_latest_manager_create_version_softlink" >> "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_mod "$script_filepath" "550" "" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_own "$script_filepath" "${username}:${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + + return 0 +} + +# 总删除软链脚本是否存在 +# 返回值0为真,1为假 +total_remove_softlink_script_exists() { + local install_path="$1" + local latest_dir="$2" + + if [ -f "$install_path/$latest_dir/$REMOVE_LATEST_SOFTLINK" ]; then + return 0 + fi + return 1 +} + +# 创建总删除软链脚本 +create_total_remove_softlink_script() { + local script_dir="$1" + local install_path="$2" + local latest_dir="$3" + local username="$4" + local usergroup="$5" + local script_filepath="$install_path/$latest_dir/$REMOVE_LATEST_SOFTLINK" + local ret + + rm -f "$script_filepath" + cat "$script_dir/common_installer.inc" > "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + add_blank_line_to_file "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + sed -n '/^## module log/,/^## end module/ p' "$script_dir/common_func.inc" >> "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + add_blank_line_to_file "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "LATEST_DIR=\"$LATEST_DIR\"" >> "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + add_blank_line_to_file "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + echo "notify_latest_manager_remove_latest_softlink" >> "$script_filepath" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_mod "$script_filepath" "550" "" + ret="$?" && [ $ret -ne 0 ] && return $ret + + change_own "$script_filepath" "${username}:${usergroup}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 删除总创建软链脚本 +del_total_create_softlink_script() { + local install_path="$1" + local latest_dir="$2" + local version="$3" + local version_dir="$4" + local script_filepath="${install_path}/${version_dir}/${CREATE_VERSION_SOFTLINK}" + local ret version_cfg_path packages + + get_version_cfg_path "version_cfg_path" "${install_path}/${latest_dir}" + if [ ! -f "${version_cfg_path}" ]; then + remove_file "${script_filepath}" "NA" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 + fi + + get_installed_packages_by_version_version_dir "packages" "${install_path}/${latest_dir}" "${version}" "${version_dir}" + if [ "${packages}" = "" ]; then + remove_file "${script_filepath}" "NA" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# 删除总删除软链脚本 +del_total_remove_softlink_script() { + local install_path="$1" + local latest_dir="$2" + local script_filepath="${install_path}/${latest_dir}/${REMOVE_LATEST_SOFTLINK}" + local ret version_cfg_path + + get_version_cfg_path "version_cfg_path" "${install_path}/${latest_dir}" + + if [ ! -f "${version_cfg_path}" ]; then + remove_file "${script_filepath}" "NA" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# platform.ini配置是否存在 +# 返回值0为真,1为假 +platform_ini_exists() { + local install_path="$1" + local latest_dir="$2" + + if [ -f "$install_path/$latest_dir/platform.ini" ]; then + return 0 + fi + return 1 +} + +# 创建platform.ini配置 +create_platform_ini() { + local install_path="$1" + local latest_dir="$2" + local username="$3" + local usergroup="$4" + local config_dirpath="${install_path}/${latest_dir}" + local config_filepath="${config_dirpath}/platform.ini" + local ret mod + + # 配置文件存在则跳过 + if [ -f "${config_filepath}" ]; then + return 0 + fi + + # 保存当前目录的权限 + get_file_mod "mod" -L "${config_dirpath}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 恢复权限 + cleanup="chmod ${mod} \"${config_dirpath}\"" + + # 添加目录写权限 + chmod u+w "${config_dirpath}" + cleanup_if_error "$?" "${cleanup}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + touch "${config_filepath}" + cleanup_if_error "$?" "${cleanup}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + change_mod "${config_filepath}" "660" "" + cleanup_if_error "$?" "${cleanup}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + change_own "${config_filepath}" "${username}:${usergroup}" + cleanup_if_error "$?" "${cleanup}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + eval "${cleanup}" + + return 0 +} + +# 删除platform.ini配置 +del_platform_ini() { + local install_path="$1" + local latest_dir="$2" + local config_dirpath="${install_path}/${latest_dir}" + local config_filepath="${config_dirpath}/platform.ini" + local ret mod + + if [ ! -f "${config_filepath}" ]; then + return 0 + fi + + # 保存当前目录的权限 + get_file_mod "mod" -L "${config_dirpath}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + # 恢复权限 + cleanup="chmod ${mod} \"${config_dirpath}\"" + + # 添加目录写权限 + chmod u+w "${config_dirpath}" + cleanup_if_error "$?" "${cleanup}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + remove_file "${config_filepath}" "NA" + cleanup_if_error "$?" "${cleanup}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + eval "${cleanup}" + + return 0 +} + +# 获取aicpu创建软链脚本路径 +get_aicpu_custom_create_softlink_path() { + local _outvar="$1" + local _install_path="$2" + local _version_dir="$3" + local _chip_name="$4" + + eval "${_outvar}=\"${_install_path}/${_version_dir}/opp/${_chip_name}/aicpu/script/aicpu_custom_create_softlink.sh\"" +} + +# 重建软链时处理aicpu软链 +deal_with_aicpu_package() { + local install_path="$1" + local version_dir="$2" + local latest_dir="$3" + local chip_name + + for chip_name in "Ascend910" "Ascend310P" "Ascend310" "Ascend310RC" "Ascend"; do + get_aicpu_custom_create_softlink_path "aicpu_script" "${install_path}" "${version_dir}" "${chip_name}" + if [ -f "${aicpu_script}" ]; then + # 创建软链时,支持强制覆盖老版本软链。 + # 因为存在这样的场景:先卸载新版本的runtime包,再卸载新版本的aicpu_kernels包, + # 卸载新版本的runtime包时触发该流程,此时老版本的aicpu_kernels包软链还在存在于环境上。 + "${aicpu_script}" --install-path="${install_path}" --version-dir="${version_dir}" --latest-dir="${latest_dir}" + # 忽略aicpu创建软链报错 + fi + done + + return 0 +} + +# 恢复可兼容的子包软链接 +recreate_compatiable_softlink_sibling_package() { + local package="$1" + + # 判断是否有本包的running版本包 + get_running_package_version "version_pair" "$scope_install_path/$scope_latest_dir" "$package" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "$version_pair" != "" ]; then + return 0 + fi + + if check_current_package_compatiable "$scope_install_path" "$scope_version" "$scope_version_dir" "$package"; then + compat_create_package_softlink_to_latest "$scope_install_path" "$package" "$scope_version" "$scope_version_dir" "$scope_latest_dir" \ + "$scope_username" "$scope_usergroup" "$scope_install_for_all" "$scope_docker_root" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + return 0 +} + +# 多版本卸载时检查版本兼容性 +recreate_compatiable_softlink_in_multi_version_uninstall() { + local scope_install_path="$1" + local scope_latest_dir="$2" + local package="$3" + local scope_username="$4" + local scope_usergroup="$5" + local scope_docker_root="$6" + local ret installed_versions version_pair version_pair_arr scope_version scope_version_dir + local scope_install_for_all version_cfg_path sibling_package + + # 切换目录避免使用uninstall.sh脚本,重建子包软链接时,找到不当前路径问题 + # sh: 0: getcwd() failed: No such file or directory + cd "${scope_install_path}" + + # 判断是否有本包的running版本包 + get_running_package_version "version_pair" "${scope_install_path}/${scope_latest_dir}" "${package}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${version_pair}" != "" ]; then + return 0 + fi + + # 枚举version.cfg中本包installed版本 + get_installed_package_versions "installed_versions" "${scope_install_path}/${scope_latest_dir}" "${package}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_install_for_all "scope_install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + INSTALL_FOR_ALL="$scope_install_for_all" + + for version_pair in ${installed_versions}; do + unpack_version_pair "version_pair_arr" "${version_pair}" + __index_list "${version_pair_arr}" 0 "scope_version" 1 "scope_version_dir" + + if check_current_package_compatiable "$scope_install_path" "$scope_version" "$scope_version_dir" "$package"; then + compat_create_package_softlink_to_latest "${scope_install_path}" "${package}" "${scope_version}" "${scope_version_dir}" "${scope_latest_dir}" \ + "${scope_username}" "${scope_usergroup}" "${scope_install_for_all}" "${scope_docker_root}" + ret="$?" && [ $ret -ne 0 ] && return $ret + + # 恢复同版本下可兼容的其他子包软链接 + get_version_cfg_path "version_cfg_path" "$scope_latest_dir" + grep -F "installed_version=" "$version_cfg_path" | grep -F "[$scope_version:$scope_version_dir]" | cut -d= -f1 | sed 's/_installed_version$//' | while read sibling_package; do + if [ "$sibling_package" != "$package" ]; then + recreate_compatiable_softlink_sibling_package "$sibling_package" + fi + done + + if [ "$package" = "runtime" ]; then + deal_with_aicpu_package "${scope_install_path}" "${scope_version_dir}" "${scope_latest_dir}" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + + break + fi + done + + return 0 +} + +# 检查包版本兼容性 +check_package_compatiable() { + local install_path="$1" + local version_left="$2" + local version_dir_left="$3" + local package_left="$4" + local version_right="$5" + local version_dir_right="$6" + local package_right="$7" + local script_dir="$8" + local pkg_version_info_path_left pkg_version_info_path_right + local required_left required_right + + get_package_version_info "pkg_version_info_path_left" "$install_path" "$version_dir_left" "$package_left" + get_package_version_info "pkg_version_info_path_right" "$install_path" "$version_dir_right" "$package_right" + + if ! _get_required_package_info "required_left" "$pkg_version_info_path_right" "$package_left"; then + return 2 + fi + if ! _get_required_package_info "required_right" "$pkg_version_info_path_left" "$package_right"; then + return 2 + fi + + if [ "$required_left" = "" ] && [ "$required_right" = "" ]; then + return 0 + fi + + if _check_version_required "$version_left" "$required_left" "$script_dir" || _check_version_required "$version_right" "$required_right" "$script_dir"; then + return 0 + fi + return 1 +} + +# 检查当前包与latest版本兼容性 +check_current_package_compatiable() { + local install_path="$1" + local current_version="$2" + local current_version_dir="$3" + local current_package="$4" + local script_dir="$install_path/$LATEST_DIR/var/manager" + local ret running_packages package version_pair version version_dir + + get_running_packages "running_packages" "$install_path/$LATEST_DIR" + for package in ${running_packages}; do + if [ "$current_package" = "$package" ]; then + continue + fi + + get_running_package_version "version_pair" "$install_path/$LATEST_DIR" "$package" + ret="$?" && [ $ret -ne 0 ] && return $ret + + unpack_version_pair "version_pair_arr" "$version_pair" + __index_list "$version_pair_arr" 0 "version" 1 "version_dir" + + if ! check_package_compatiable "$install_path" "$current_version" "$current_version_dir" "$current_package" \ + "$version" "$version_dir" "$package" "$script_dir"; then + return 1 + fi + done + + return 0 +} + +# 多版本安装时检查版本兼容性 +check_compatiable_in_multi_version_install() { + local install_path="$1" + local username="$2" + local docker_root="$3" + local current_version="$4" + local current_version_dir="$5" + local current_package="$6" + local script_dir="$install_path/$LATEST_DIR/var/manager" + local ret running_packages package version_pair version version_dir + + get_running_packages "running_packages" "$install_path/$LATEST_DIR" + for package in ${running_packages}; do + if [ "$current_package" = "$package" ]; then + continue + fi + + get_running_package_version "version_pair" "$install_path/$LATEST_DIR" "$package" + ret="$?" && [ $ret -ne 0 ] && return $ret + + unpack_version_pair "version_pair_arr" "$version_pair" + __index_list "$version_pair_arr" 0 "version" 1 "version_dir" + + if ! check_package_compatiable "$install_path" "$current_version" "$current_version_dir" "$current_package" \ + "$version" "$version_dir" "$package" "$script_dir"; then + compat_del_package_softlink_in_latest "$install_path" "$package" "$version" "$version_dir" \ + "$LATEST_DIR" "$username" "$docker_root" + ret="$?" && [ $ret -ne 0 ] && return $ret + fi + done + + return 0 +} + +# 创建版本包目录软链接到latest目录下 +create_package_dir_softlink_to_latest() { + local install_path="$1" + local version_dir="$2" + local latest_dir="$3" + local package="$4" + local username="$5" + local usergroup="$6" + local install_for_all="$7" + local ret package_dirpath package_prefix + + get_package_dirpath "package_dirpath" "${package}" + package_prefix="$(dirname "${package_dirpath}")" + + if [ ! -d "${install_path}/${version_dir}/${package_dirpath}" ]; then + return 0 + fi + + if [ ! -d "${install_path}/${latest_dir}/${package_prefix}" ]; then + make_dir_with_permission "${install_path}/${latest_dir}/${package_prefix}" "750" "${username}" "${usergroup}" "${install_for_all}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + + create_softlink_icp "-r" "${install_path}/${version_dir}/${package_dirpath}" "${install_path}/${latest_dir}/${package_dirpath}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + return 0 +} + +# 删除latest目录下版本包目录的软链接 +del_package_dir_softlink_in_latest() { + local install_path="$1" + local latest_dir="$2" + local package="$3" + local ret package_dirpath package_prefix + + get_package_dirpath "package_dirpath" "${package}" + package_prefix="$(dirname "${package_dirpath}")" + + remove_softlink_icp "${install_path}/${latest_dir}/${package_dirpath}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + + if [ "${package_prefix}" != "." ]; then + remove_dir_if_empty "${install_path}/${latest_dir}/${package_prefix}" + ret="$?" && [ ${ret} -ne 0 ] && return ${ret} + fi + + return 0 +} + +# 生成包db.info条目列表 +packages_db_items() { + local install_path="$1" + local running_packages="$2" + local total_ret=0 ret running_packages package version_pair version_pair_arr version version_dir + local install_type feature_type feature_param filelist_path install_info_path + + for package in $running_packages; do + if ! get_running_package_version "version_pair" "$install_path/$LATEST_DIR" "$package"; then + total_ret=1 + continue + fi + + unpack_version_pair "version_pair_arr" "$version_pair" + __index_list "$version_pair_arr" 0 "version" 1 "version_dir" + + get_package_filelist "filelist_path" "$install_path" "$version_dir" "$package" + get_package_install_info "install_info_path" "$install_path" "$version_dir" "$package" + + check_file_exists "$install_info_path" "$install_info_path doesn't exist in create package softlink to latest!" + ret="$?" && [ $ret -ne 0 ] && total_ret=1 && continue + + get_package_install_type "install_type" "$install_info_path" "$package" + check_ret_error "$?" "Get install_type from ascend_install.info failed in create package softlink to latest!" + ret="$?" && [ $ret -ne 0 ] && total_ret=1 && continue + + get_package_feature_type "feature_type" "$install_info_path" "$package" "install" + check_ret_error "$?" "Get feature_type from ascend_install.info failed in create package softlink to latest!" + ret="$?" && [ $ret -ne 0 ] && total_ret=1 && continue + + get_package_chip_type "chip_type" "$install_info_path" "$package" "install" + check_ret_error "$?" "Get chip_type from ascend_install.info failed in create package softlink to latest!" + ret="$?" && [ $ret -ne 0 ] && total_ret=1 && continue + + pack_feature_param "feature_param" "${feature_type}" "n" "${chip_type}" + + all_common_dirs_blocks_in_filelist "$install_type" "$filelist_path" "$feature_param" \ + | blocks_to_db_item "$package" "$version_dir" + ret="$?" && [ $ret -ne 0 ] && total_ret=1 && continue + done + + return $total_ret +} + +# 生成运行包的ascend_package_db.info +generate_running_packages_db_info() { + local var_path="$1" + local ret install_path running_packages db_info install_for_all + local db_info_path="$var_path/ascend_package_db.info" + + install_path="$(dirname "$(dirname "$var_path")")" + + if [ -f "$db_info_path" ]; then + return 0 + fi + + get_running_packages "running_packages" "$install_path/$LATEST_DIR" + ret="$?" && [ $ret -ne 0 ] && return $ret + + if [ "${running_packages}" = "" ]; then + return 0 + fi + + db_info="$( + packages_db_items "$install_path" "$running_packages" \ + | remove_blank_line | sort_1 "|" | fold_2 "|" "" + )" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_install_for_all "install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + + ensure_file "$db_info_path" "440" "$USERNAME" "$USERGROUP" "$install_for_all" + ret="$?" && [ $ret -ne 0 ] && return $ret + + with_chmod "$db_info_path" "700" write_text "$db_info" "$db_info_path" + ret="$?" && [ $ret -ne 0 ] && return $ret + + return 0 +} + +# 升级setenv脚本 +upgrade_setenv() { + local latest_path="$1" + local shell_type config_path + for shell_type in ${ENV_SHELL_TYPES}; do + get_setenv_filepath "config_path" "$latest_path" "$shell_type" + add_ascend_home_path_env "$config_path" "$shell_type" "$latest_path" + done +} + +# latest下数据迁移 +migrate_latest_data() { + local var_path="$1" + local latest_path="$(dirname "$var_path")" + local ret config_path + + generate_running_packages_db_info "$var_path" + ret="$?" && [ $ret -ne 0 ] && return $ret + + get_setenv_filepath "config_path" "$latest_path" "bash" + if ! has_ascend_home_path_env "$config_path"; then + with_chmod "$latest_path/bin" "700" upgrade_setenv "$latest_path" + fi + + return 0 +} diff --git a/scripts/package/latest_manager/scripts/uninstall.sh b/scripts/package/latest_manager/scripts/uninstall.sh new file mode 100644 index 0000000000000000000000000000000000000000..8dd5a9afe3bfceff47f4fe1360e42166b0ccf4a1 --- /dev/null +++ b/scripts/package/latest_manager/scripts/uninstall.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +CURPATH=$(dirname $(readlink -f "$0")) +VARPATH="$(dirname "$CURPATH")" +USERNAME=$(id -un) +USERGROUP=$(id -gn) +common_func_path="$CURPATH/common_func.inc" +manager_func_path="$CURPATH/manager_func.sh" + +. "$common_func_path" +. "$manager_func_path" + +set_comm_log "Latest_manager" "$COMM_LOGFILE" + +IS_UPGRADE="n" + +while true +do + case "$1" in + --upgrade) + IS_UPGRADE="y" + shift + ;; + *) + break + ;; + esac +done + +if ! sh "$CURPATH/install_common_parser.sh" --package="latest_manager" --uninstall --username="$USERNAME" --usergroup="$USERGROUP" \ + --simple-uninstall "full" "$VARPATH" "$CURPATH/filelist.csv" "all"; then + comm_log "ERROR" "uninstall failed!" + exit 1 +fi + +if [ "$IS_UPGRADE" = "n" ]; then + remove_manager_refs "$VARPATH" +fi + +if ! remove_dir_if_empty "$VARPATH"; then + comm_log "ERROR" "uninstall failed!" + exit 1 +fi diff --git a/scripts/package/latest_manager/scripts/version.info b/scripts/package/latest_manager/scripts/version.info new file mode 100644 index 0000000000000000000000000000000000000000..526e64acf75b28424a5c78b233b5562a729fbc1b --- /dev/null +++ b/scripts/package/latest_manager/scripts/version.info @@ -0,0 +1 @@ +Version=45 diff --git a/scripts/package/metadef/metadef.xml b/scripts/package/metadef/metadef.xml new file mode 100644 index 0000000000000000000000000000000000000000..80df6f7281d2e7dfe124208d6d85db57771c01e1 --- /dev/null +++ b/scripts/package/metadef/metadef.xml @@ -0,0 +1,55 @@ + + + + cann + metadef + run + metadef/script/install.sh + metadef/script/help.info + package/metadef/version.xml + metadef/script/cleanup.sh + true + true + + + $(VERSION_DIR) + $(TIMESTAMP_NO) + + + $(OS_NAME) + $(OS_VER) + $(ARCH) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/package/metadef/scripts/cleanup.sh b/scripts/package/metadef/scripts/cleanup.sh new file mode 100644 index 0000000000000000000000000000000000000000..a56989b93519a2b602e8189ad83300c74e76be9c --- /dev/null +++ b/scripts/package/metadef/scripts/cleanup.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +set -e + +rm -rf $(pwd) diff --git a/scripts/package/metadef/scripts/help.info b/scripts/package/metadef/scripts/help.info new file mode 100644 index 0000000000000000000000000000000000000000..c75b0814abbc362dc4a40ac376ffef7b4b62e581 --- /dev/null +++ b/scripts/package/metadef/scripts/help.info @@ -0,0 +1,38 @@ + --run Install run mode + --docker-root= Specify the path of docker root + --install-path= Install product to specific dir path + --install-for-all Install for all user + --pylocal Install python packages to install dir path + --chip= Nothing is currently supported + --feature= Nothing is currently supported + --setenv Setting the Environment Variables Required at Run Time + --devel Install devel mode + --docker-root= Specify the path of docker root + --install-path= Install product to specific dir path + --install-for-all Install for all user + --pylocal Install python packages to install dir path + --chip= Nothing is currently supported + --feature= Nothing is currently supported + --setenv Setting the Environment Variables Required at Run Time + --full Install full mode + --docker-root= Specify the path of docker root + --install-path= Install product to specific dir path + --install-for-all Install for all user + --pylocal Install python packages to install dir path + --chip= Nothing is currently supported + --feature= Nothing is currently supported + --setenv Setting the Environment Variables Required at Run Time + --uninstall Uninstall product + --docker-root= Specify the path of docker root + --install-path= Uninstall product to specific dir path + --upgrade Upgrade product immediately + --docker-root= Specify the path of docker root + --install-path= Install product to specific dir path + --install-for-all Install for all user + --pylocal Install python packages to install dir path + --chip= Nothing is currently supported + --feature= Nothing is currently supported + --setenv Setting the Environment Variables Required at Run Time + --version Query the package version + --pre-check Package installation/running pre-dependency check + \ No newline at end of file diff --git a/scripts/package/metadef/scripts/install.sh b/scripts/package/metadef/scripts/install.sh new file mode 100644 index 0000000000000000000000000000000000000000..c1de529f3b694d659ebcfa35b971ed7dac61a5e2 --- /dev/null +++ b/scripts/package/metadef/scripts/install.sh @@ -0,0 +1,1445 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +default_root_dir="/usr/local/Ascend" +default_normal_dir="${HOME}/Ascend" +username=$(id -un) +usergroup=$(id -gn) +curpath=$(dirname $(readlink -f "$0")) +common_func_path="${curpath}/common_func.inc" +version_compat_func_path="${curpath}/version_compatiable.inc" +common_func_v2_path="${curpath}/common_func_v2.inc" +version_cfg_path="${curpath}/version_cfg.inc" +metadef_func_path="${curpath}/metadef_func.sh" +pkg_version_path="${curpath}/../../version.info" +install_info_old="/etc/ascend_install.info" +run_dir="$(echo "$2" | cut -d'-' -f 3-)" + +. "${common_func_path}" +. "${version_compat_func_path}" +. "${common_func_v2_path}" +. "${version_cfg_path}" +. "${metadef_func_path}" + +if [ "$(id -u)" != "0" ]; then + log_dir="${HOME}/var/log/ascend_seclog" +else + log_dir="/var/log/ascend_seclog" +fi + +if [ ! -d "$log_dir" ]; then + mkdir -p "$log_dir" +fi + +operation_logfile="${log_dir}/operation.log" +logfile="${log_dir}/ascend_install.log" + +# 递归授权 +chmod_recur() { + local file_path="${1}" + local permission="${2}" + local type="${3}" + permission=$(set_file_chmod "$permission") + if [ "$type" = "dir" ]; then + find "$file_path" -type d -exec chmod "$permission" {} \; 2> /dev/null + elif [ "$type" = "file" ]; then + find "$file_path" -type f -exec chmod "$permission" {} \; 2> /dev/null + fi +} + +# 单目录授权 +chmod_single_dir() { + local file_path="${1}" + local permission="${2}" + local type="${3}" + permission=$(set_file_chmod "$permission") + if [ "$type" = "dir" ]; then + chmod "$permission" "$file_path" + elif [ "$type" = "file" ]; then + chmod "$permission" "$file_path" + fi +} + +# 设置权限 +set_file_chmod() { + local permission="${1}" + local new_permission="" + if [ "${input_install_for_all}" = "y" ]; then + new_permission="$(expr substr $permission 1 2)$(expr substr $permission 2 1)" + echo "$new_permission" + else + echo "$permission" + fi +} + +# 运行前授权 +chmod_start() { + local tmpdir="$1" + [ -z "$tmpdir" ] && tmpdir="$default_dir" + chmod_recur "$tmpdir" 750 dir 2> /dev/null + chmod_recur "$tmpdir/python" 750 dir 2> /dev/null +} + +# 运行结束授权 +chmod_end() { + local current_install_path="$pkg_install_path" + if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" != "y" ]; then + current_install_path="$current_install_path/$pkg_version_dir" + fi + + # data dir/file permission + chmod_recur "$default_dir/python" 750 dir + chmod_recur "$current_install_path/python" 750 dir + + if [ "$pylocal" = "y" ]; then + chmod_recur "$current_install_path/python/site-packages/superkernel" 550 dir + chmod_recur "$current_install_path/python/site-packages/superkernel" 550 file + chmod_recur "$current_install_path/python/site-packages/superkernel-0.1.0.dist-info" 550 dir + chmod_recur "$current_install_path/python/site-packages/superkernel-0.1.0.dist-info" 550 file + chmod_recur "$current_install_path/python/site-packages/LICENSE" 440 file + fi + + chmod_single_dir "$default_dir/ascend_install.info" 640 file 2> /dev/null + chmod_single_dir "$default_dir/version.info" 440 file 2> /dev/null + chmod_single_dir "$default_dir/scene.info" 640 file 2> /dev/null + chmod_single_dir "$default_dir" 550 dir 2> /dev/null + chmod_single_dir "$default_dir/script" 550 dir 2> /dev/null + chmod_recur "$default_dir/script" 550 file 2> /dev/null + chown -R "$username":"$usergroup" "$default_dir" 2> /dev/null + if [ $(id -u) -eq 0 ]; then + chown "root:root" "$default_dir" 2> /dev/null + chmod 755 "$default_dir" 2> /dev/null + chown -R "root:root" "$default_dir/script" 2> /dev/null + fi +} + +ver_check() { + local version_info_file="" + if [ -f "${install_info_old}" ] && [ $(grep -c -i driver_install_path_param "$install_info_old") -ne 0 ]; then + if [ -f "${default_dir}/version.info" ]; then + version_info_file="${default_dir}/version.info" + else + version_info_file="$pkg_version_path" + fi + local driver_install_path_param="$(grep -iw driver_install_path_param "${install_info_old}" | cut -d"=" -f2-)" + local dep_pkg_ver_file="${driver_install_path_param}/driver/version.info" + if [ "$check" = "y" ]; then + bash "${curpath}/ver_check.sh" "${version_info_file}" "driver" "${dep_pkg_ver_file}" + elif [ "$full_install" = "y" ] || [ "$run_install" = "y" ] || [ "$devel_install" = "y" ] || [ "$upgrade" = "y" ]; then + bash "${curpath}/ver_check.sh" "${version_info_file}" "driver" "${dep_pkg_ver_file}" 1> /dev/null + local ret=$? + if [ "${ret}" -eq 1 ] && [ "$is_quiet" = "n" ]; then + log "WARNING" "Check version does not matched, do you want to continue? [y/n]" + while true + do + read yn + if [ "$yn" = "n" ]; then + log "INFO" "stop installation!" + exit_install_log 0 + elif [ "$yn" = "y" ]; then + break + else + log "ERROR" "ERR_NO:0x0002;ERR_DES:input error, please input again!" + fi + done + elif [ "${ret}" -eq 1 ] && [ "$is_quiet" = "y" ]; then + log "WARNING" "Check version does not matched!" + elif [ "${ret}" -eq 0 ]; then + log "INFO" "Check version matched!" + fi + fi + else + log "WARNING" "Cannot find the install path of driver." + fi +} + +param_usage() { + log "INFO" "Please input this command for help: ./${runfilename} --help" +} + +# 修改日志文件的权限 +change_log_mode() { + if [ ! -f "$logfile" ]; then + touch "$logfile" + fi + chmod 640 "$logfile" +} + +# 创建日志文件夹 +create_log_folder() { + if [ ! -d "$log_dir" ]; then + mkdir -p "$log_dir" + fi + if [ $(id -u) -ne 0 ]; then + chmod 740 "$log_dir" + else + chmod 750 "$log_dir" + fi +} + +# 写日志 +log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + local log_type="$1" + local log_msg="$2" + local log_format="[metadef] [$cur_date] [$log_type]: $log_msg" + if [ "$log_type" = "INFO" ]; then + echo "$log_format" + elif [ "$log_type" = "WARNING" ]; then + echo "$log_format" + elif [ "$log_type" = "ERROR" ]; then + echo "$log_format" + elif [ "$log_type" = "DEBUG" ]; then + echo "$log_format" 1> /dev/null + fi + if [ -d "$log_dir" ]; then + echo "$log_format" >> "$logfile" + fi +} + +# 静默模式日志打印 +new_echo() { + local log_type="$1" + local log_msg="$2" + if [ "${is_quiet}" = "n" ]; then + echo "${log_type}" "${log_msg}" 1> /dev/null + fi +} + +# 开始安装前打印开始信息 +start_install_log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + new_echo "INFO" "Start time:${cur_date}" + log "INFO" "Start time:$cur_date" + log "INFO" "LogFile:${logfile}" + log "INFO" "InputParams:$all_parma" + log "INFO" "OperationLogFile:${operation_logfile}" +} + +# 开始卸载前打印开始信息 +start_uninstall_log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + new_echo "INFO" "Start time:${cur_date}" + log "INFO" "Start time:$cur_date" + log "INFO" "LogFile:${logfile}" + log "INFO" "InputParams:$all_parma" + log "INFO" "OperationLogFile:${operation_logfile}" +} + +# 安装结束退出前打印结束信息 +exit_install_log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + new_echo "INFO" "End time:${cur_date}" + log "INFO" "End time:${cur_date}" + exit "$1" +} + +# 安装结束退出前打印结束信息 +exit_uninstall_log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + new_echo "INFO" "End time:${cur_date}" + log "INFO" "End time:${cur_date}" + exit "$1" +} + +# 安全日志 +log_operation() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + local level="" + if [ "$1" = "Install" ]; then + level="SUGGESTION" + elif [ "$1" = "Upgrade" ]; then + level="MINOR" + elif [ "$1" = "Uninstall" ]; then + level="MAJOR" + else + level="UNKNOWN" + fi + + if [ ! -f "${operation_logfile}" ]; then + touch "${operation_logfile}" + chmod 640 "${operation_logfile}" + fi + + echo "$1 $level root $cur_date 127.0.0.1 $runfilename $2 installmode=$installmode; cmdlist=$all_parma" >> "$operation_logfile" +} + +# 相对路径转化绝对路径 +relative_path_to_absolute_path() { + local relative_path_="${1}" + if [ "x$relative_path_" = "x" ]; then + return + fi + local fstr="$(expr substr "$relative_path_" 1 1)" + if [ "$fstr" = "~" ]; then + relative_path_="${HOME}$(echo "${relative_path_}" | cut -d'~' -f 2-)" + elif [ "$fstr" != "/" ]; then + relative_path_="${run_dir}/${relative_path_}" + fi + echo "$relative_path_" +} + +# 获取安装路径 +get_install_path() { + local ppath="" + if [ "$input_path_flag" = "y" ]; then + if [ "x${input_install_path}" = "x" ]; then + log "ERROR" "ERR_NO:0x0004;ERR_DES: Install path is empty." + exitLog 1 + fi + fi + input_install_path=$(echo "${input_install_path}" | sed "s/\/*$//g") + if [ "x${input_install_path}" = "x" ]; then + input_install_path="/" + fi + if [ "$uninstall" != "y" ]; then + ppath=$(echo "${input_install_path}" | sed "s/\/[^/]*$//g") + if [ "x${ppath}" != "x" ] && [ ! -d "${ppath}" ]; then + log "ERROR" "parent path doesn't exist, please create ${ppath} first." + exitLog 1 + fi + fi +} + +create_install_dir() { + local path="$1" + local user_and_group="$2" + local permission="" + + if [ $(id -u) -eq 0 ]; then + user_and_group="root:root" + permission=755 + else + if [ "$input_install_for_all" = "y" ]; then + permission=755 + else + permission=750 + fi + fi + + if [ "x${path}" = "x" ]; then + log "WARNING" "dir path is empty" + return 1 + fi + mkdir -p "${path}" + if [ $? -ne 0 ]; then + log "WARNING" "create path=${path} failed." + return 1 + fi + chmod "$permission" "${path}" + if [ $? -ne 0 ]; then + log "WARNING" "chmod path=${path} $permission failed." + return 1 + fi + chown -f "$user_and_group" "${path}" + if [ $? -ne 0 ]; then + log "WARNING" "chown path=${path} $user_and_group failed." + return 1 + fi +} + +create_file() { + local _file="$1" + if [ -d "${_file}" ]; then + rm -rf "${_file}" + fi + touch "${_file}" + chown "$2" "${_file}" + chmod_single_dir "${_file}" "$3" file + if [ $? -ne 0 ]; then + return 1 + fi + return 0 +} + +# 判断输入的指定路径是否存在 +is_valid_path() { + if [ "x${pkg_install_path}" != "x" ]; then + if [ ! -d "${pkg_install_path}" ]; then + local up_dir=$(dirname "${pkg_install_path}") + if [ ! -d "${up_dir}" ]; then + log "ERROR" "ERR_NO:0x0003;ERR_DES:The $up_dir dose not exist, please retry a right path." + exit_install_log 1 + fi + else + local install_path="$pkg_install_path" + if [ "$hetero_arch" = "y" ]; then + install_path="$(realpath $install_path/../..)" + fi + local ret=0 + if [ $(id -u) -eq 0 ]; then + parent_dirs_permission_check "$install_path" && ret=$? || ret=$? + if [ "${is_quiet}" = "y" ] && [ "${ret}" -ne 0 ]; then + log "ERROR" "the given dir, or its parents, permission is invalid." + exit 1 + fi + if [ "${ret}" -ne 0 ]; then + log "WARNING" "You are going to put run-files on a unsecure install-path, do you want to continue? [y/n]" + while true + do + read yn + if [ "$yn" = "n" ]; then + exit 1 + elif [ "$yn" = "y" ]; then + break + else + echo "ERR_NO:0x0002;ERR_DES:input error, please input again!" + fi + done + fi + fi + if [ $(id -u) -ne 0 ]; then + log "DEBUG" "$install_path" + else + sh -c 'cd "$install_path" >> /dev/null 2>&1' + fi + if [ $? != 0 ]; then + log "ERROR" "ERR_NO:0x0093;ERR_DES:The $username do not have the permission to access $install_path, please reset the directory to a right permission." + exit_install_log 1 + fi + fi + fi +} + +# 递归判断安装路的属组和权限 +parent_dirs_permission_check() { + local current_dir="$1" + local parent_dir="" + local short_install_dir="" + local owner="" + local mod_num="" + + parent_dir=$(dirname "${current_dir}") + short_install_dir=$(basename "${current_dir}") + log "INFO" "parent_dir value is [${parent_dir}] and children_dir value is [${short_install_dir}]" + + if [ "x${current_dir}" = "x/" ]; then + log "INFO" "parent_dirs_permission_check succeeded" + return 0 + else + owner=$(stat -c %U "${parent_dir}/${short_install_dir}") + if [ "${owner}" != "root" ]; then + log "WARNING" "[${short_install_dir}] permission isn't right, it should belong to root." + return 1 + fi + log "INFO" "[${short_install_dir}] belongs to root." + + mod_num=$(stat -c %a "${parent_dir}/${short_install_dir}") + mod_num=$(check_chmod_length "$mod_num") + if [ "${mod_num}" -lt 755 ]; then + log "WARNING" "[${short_install_dir}] permission is too small, it is recommended that the permission be 755 for the root user." + return 2 + elif [ "${mod_num}" -eq 755 ]; then + log "INFO" "[${short_install_dir}] permission is ok." + else + log "WARNING" "[${short_install_dir}] permission is too high, it is recommended that the permission be 755 for the root user." + [ "${is_quiet}" = "n" ] && return 3 + fi + parent_dirs_permission_check "${parent_dir}" + fi +} + +check_chmod_length() { + local mod_num="$1" + local new_mod_num="" + local mod_num_length=$(expr length "$mod_num") + if [ "$mod_num_length" -eq 3 ]; then + new_mod_num="$mod_num" + echo "$new_mod_num" + elif [ "$mod_num_length" -eq 4 ]; then + new_mod_num="$(expr substr $mod_num 2 3)" + echo "$new_mod_num" + fi +} + +# 校验用户和组的关联关系 +check_group() { + local group_user_related="" + local result="$(groups "$2" | grep ":")" + if [ "x${result}" != "x" ]; then + group_user_related=$(groups "$2"|awk -F":" '{print $2}'|grep -w "$1") + else + group_user_related=$(groups "$2"|grep -w "$1") + fi + if [ "x${group_user_related}" != "x" ]; then + return 0 + else + return 1 + fi +} + +# 解锁 +unchattr_files() { + if [ -f "$install_info" ]; then + if [ -d "$default_dir" ]; then + chattr -R -i "$default_dir" >> /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "DEBUG" "unchattr -i for the subfiles." + find "$default_dir" -name "*" | xargs chattr -i >> /dev/null 2>&1 + else + log "DEBUG" "unchattr -R -i $pkg_install_path succeeded." + fi + fi + fi +} + +# 创建普通用户的默认安装目录 +create_default_install_dir_for_common_user() { + if [ "$full_install" = "y" ] || [ "$run_install" = "y" ] || [ "$devel_install" = "y" ]; then + if [ ! -d "$pkg_install_path" ]; then + create_install_dir "$pkg_install_path" "$username:$usergroup" + fi + if [ "$hetero_arch" = "y" ]; then + local parent_dir="$(dirname "$pkg_install_path")" + create_install_dir "$parent_dir" "$username:$usergroup" + fi + fi +} + +# 创建子包安装目录 +create_default_dir() { + if [ ! -d "$default_dir" ]; then + create_install_dir "$default_dir" "${username}":"${usergroup}" + fi + if [ -n "$pkg_version_dir" ] && [ "$hetero_arch" != "y" ]; then + create_install_dir "$(dirname $default_dir)" "$username:$usergroup" + fi + [ -d "$default_dir" ] && return 0 + return 1 +} + +# 获取安装目录下的完整版本号 +get_version_installed() { + local installed_version="none" + if [ -f "$default_dir/version.info" ]; then + installed_version="$(grep -iw ^version "$default_dir/version.info" | cut -d"=" -f2-)" + fi + echo "$installed_version" +} + +# 获取本包中的完整版本号 +get_version_in_runpkg() { + local version_in_runpkg="none" + if [ -f "$pkg_version_path" ]; then + version_in_runpkg="$(grep -iw ^version $pkg_version_path | cut -d"=" -f2-)" + fi + echo "$version_in_runpkg" +} + +# 更新基础版本号 +update_version_info_version() { + if [ -f "$default_dir/version.info" ]; then + rm -f "$default_dir/version.info" + cp -f "$pkg_version_path" "$default_dir" + log "INFO" "Upgrade base version successfully!" + else + cp -f "$pkg_version_path" "$default_dir" + log "INFO" "Base version set successfully!" + fi + chmod_single_dir "$default_dir/version.info" 440 file >> /dev/null 2>&1 +} + +log_base_version() { + if [ -f "$install_info" ]; then + local installed_version="$(get_version_installed)" + if [ "x${installed_version}" != "x" ]; then + new_echo "INFO" "base version is ${installed_version}." + log "INFO" "base version is ${installed_version}." + return 0 + fi + fi + if [ "$upgrade" = "y" ]; then + new_echo "WARNING" "base version was destroyed or not exist." + log "WARNING" "base version was destroyed or not exist." + fi +} + +update_install_path() { + if [ ! -d "$pkg_install_path" ]; then + log "ERROR" "ERR_NO:0x0003;ERR_DES:The $pkg_install_path dose not exist, please retry a right path." + exit_install_log 1 + fi +} + +update_install_param() { + local _key="$1" + local _val="$2" + local _file="$3" + local _param="" + if [ ! -f "${_file}" ]; then + exit 1 + fi + local install_info_key_array="METADEF_Install_Type METADEF_Chip_Type METADEF_Feature_Type METADEF_UserName METADEF_UserGroup METADEF_Install_Path_Param METADEF_Arch_Linux_Path METADEF_Hetero_Arch_Flag" + for key_param in ${install_info_key_array}; do + if [ "${key_param}" = "${_key}" ]; then + _param=$(grep -i "${_key}=" "${_file}") + if [ "x${_param}" = "x" ]; then + echo "${_key}=${_val}" >> "${_file}" + else + sed -i "/^${_key}=/Ic ${_key}=${_val}" "${_file}" 2> /dev/null + fi + break + fi + done +} + +get_install_param() { + local _key="$1" + local _file="$2" + local _param="" + + if [ ! -f "${_file}" ]; then + exit 1 + fi + local install_info_key_array="METADEF_Install_Type METADEF_Chip_Type METADEF_Feature_Type METADEF_UserName METADEF_UserGroup METADEF_Install_Path_Param METADEF_Arch_Linux_Path METADEF_Hetero_Arch_Flag" + for key_param in ${install_info_key_array}; do + if [ "${key_param}" = "${_key}" ]; then + _param=$(grep -i "${_key}=" "${_file}" | cut -d"=" -f2-) + break + fi + done + echo "${_param}" +} + +update_install_info_feature() { + local operation="$1" + if [ "$featuremode" = "all" ] || [ "$operation" = "Upgrade" ]; then + update_install_param "METADEF_Feature_Type" "$featuremode" "$install_info" + return + fi + local current_featuremode=$(get_install_param "METADEF_Feature_Type" "$install_info") + if [ -z "$current_featuremode" ] || [ "$current_featuremode" = "all" ]; then + update_install_param "METADEF_Feature_Type" "$featuremode" "$install_info" + return + fi + local version_in_runpkg="$(get_version_in_runpkg)" + if [ "$version_in_runpkg" != "$version_installed" ]; then + update_install_param "METADEF_Feature_Type" "$featuremode" "$install_info" + return + fi + featuremode=$(echo "$current_featuremode,$featuremode" | tr ',' '\n' | sort -u | tr '\n' ',' | sed -e 's/^,\+\|,\+$//g') + update_install_param "METADEF_Feature_Type" "$featuremode" "$install_info" +} + +update_install_info() { + chmod_start + if [ ! -f "$install_info" ]; then + create_file "$install_info" "$username":"$usergroup" 640 + fi + update_install_param "METADEF_Install_Type" "$installmode" "$install_info" + update_install_param "METADEF_Chip_Type" "$chipmode" "$install_info" + update_install_info_feature + update_install_param "METADEF_UserName" "$username" "$install_info" + update_install_param "METADEF_UserGroup" "$usergroup" "$install_info" + update_install_param "METADEF_Install_Path_Param" "$install_path_param" "$install_info" + update_install_param "METADEF_Arch_Linux_Path" "$arch_linux_path" "$install_info" + update_install_param "METADEF_Hetero_Arch_Flag" "$hetero_arch" "$install_info" +} + +prompt_set_env() { + local install_path="$1" + if [ -n "$pkg_version_dir" ] && [ "$hetero_arch" != "y" ]; then + install_path="$install_path/$pkg_version_dir" + fi + if [ "$hetero_arch" = "y" ]; then + echo "Please make sure that + - PATH includes ${install_path}/metadef/bin + - LD_LIBRARY_PATH includes ${install_path}/metadef/lib64" + else + echo "Please make sure that + - PATH includes ${install_path}/metadef/bin + - LD_LIBRARY_PATH includes ${install_path}/metadef/lib64 + - PYTHONPATH includes ${install_path}/metadef/python/site-packages" + fi +} + +check_docker_path() { + local docker_path="$1" + if [ $(expr substr "${docker_path}" 1 1) != "/" ]; then + log "ERROR" "ERR_NO:0x0002;ERR_DES:Parameter --docker-root \ + must with absolute path that which is start with root directory /. Such as --docker-root=/${docker_path}" + exit 1 + fi + if [ ! -d "${docker_path}" ]; then + log "ERROR" "ERR_NO:${FILE_NOT_EXIST}; The directory:${docker_path} not exist, please create this directory." + exit 1 + fi +} + +concat_docker_install_path() { + local docker_path="$1" + local install_path="" + docker_path=$(echo "${docker_path}" | sed "s/\/*$//g") + if [ "x${docker_path}" = "x" ]; then + docker_path="/" + fi + install_path="${docker_path}$2" + echo "${install_path}" +} + +####################################################### +# 安装调用子脚本 +install_run() { + local operation="Install" + local metadef_install_path_param="" + update_install_path + update_install_info + local metadef_input_install_path=$(get_install_param "METADEF_Install_Path_Param" "${install_info}") + local metadef_install_type=$(get_install_param "METADEF_Install_Type" "${install_info}") + if [ "$is_docker_install" = "y" ]; then + metadef_install_path_param=$(concat_docker_install_path "${docker_root}" "${metadef_input_install_path}") + else + metadef_install_path_param="${metadef_input_install_path}" + fi + if [ "$1" = "install" ]; then + unchattr_files + chmod_start + new_echo "INFO" "install ${metadef_install_path_param} ${metadef_install_type}" + log "INFO" "install ${metadef_install_path_param} ${metadef_install_type}" + bash "${curpath}/run_metadef_install.sh" "install" "${metadef_input_install_path}" "${metadef_install_type}" \ + "${is_quiet}" "${pylocal}" "${input_setenv}" "${docker_root}" "${in_install_for_all}" + if [ $? -eq 0 ]; then + update_version_info_version + log "INFO" "metadef package installed successfully! The new version takes effect immediately." + log_operation "${operation}" "succeeded" + chmod_end + prompt_set_env "${install_path_param}" + else + chmod_end + log "ERROR" "metadef package install failed, please retry after uninstall!" + log_operation "${operation}" "failed!" + exit_install_log 1 + fi + fi + return $? +} + +# 升级调用子脚本 +upgrade_run() { + local operation="Upgrade" + local metadef_install_path_param="" + update_install_info_feature "$operation" + if [ -f "$install_info" ]; then + local metadef_input_install_path=$(get_install_param "METADEF_Install_Path_Param" "${install_info}") + local metadef_install_type=$(get_install_param "METADEF_Install_Type" "${install_info}") + elif [ -f "$install_info_old" ] && [ $(grep -c -i metadef_install_path_param "$install_info_old") -ne 0 ]; then + local metadef_input_install_path="$(grep -iw metadef_install_path_param "$install_info_old" | cut -d"=" -f2-)" + local metadef_install_type="$(grep -iw metadef_install_type "$install_info_old" | cut -d"=" -f2-)" + else + log "ERROR" "ERR_NO:0x0080;ERR_DES:Installation information no longer exists, please complete ${install_info} or ${install_info_old}" + exit_install_log 1 + fi + if [ "$is_docker_install" = "y" ]; then + metadef_install_path_param=$(concat_docker_install_path "${docker_root}" "${metadef_input_install_path}") + else + metadef_install_path_param="${metadef_input_install_path}" + fi + if [ "$1" = "upgrade" ]; then + chmod_start + new_echo "INFO" "upgrade ${metadef_install_path_param} ${metadef_install_type}" + log "INFO" "upgrade ${metadef_install_path_param} ${metadef_install_type}" + bash "${curpath}/run_metadef_upgrade.sh" "upgrade" "${metadef_input_install_path}" "${metadef_install_type}" \ + "${is_quiet}" "${pylocal}" "${input_setenv}" "${docker_root}" "${in_install_for_all}" + if [ $? -eq 0 ]; then + update_version_info_version + log "INFO" "metadef package upgraded successfully! The new version takes effect immediately." + log_operation "${operation}" "succeeded" + chmod_end + prompt_set_env "${install_path_param}" + else + chmod_end + log "ERROR" "metadef package upgrade failed, please retry after uninstall!" + log_operation "${operation}" "failed!" + exit_install_log 1 + fi + fi + return $? +} + +# 卸载调用子脚本 +uninstall_run() { + local is_recreate_softlink="$2" + local is_remove_info_files="$3" + local upgrade_install_info="$4" + [ -z "$upgrade_install_info" ] && upgrade_install_info="$install_info" + local operation="Uninstall" + local metadef_install_path_param="" + if [ -f "$upgrade_install_info" ]; then + local metadef_input_install_path=$(get_install_param "METADEF_Install_Path_Param" "${upgrade_install_info}") + local metadef_install_type=$(get_install_param "METADEF_Install_Type" "${upgrade_install_info}") + elif [ -f "$install_info_old" ] && [ $(grep -c -i metadef_install_path_param "$install_info_old") -ne 0 ]; then + local metadef_input_install_path="$(grep -iw metadef_install_path_param "$install_info_old" | cut -d"=" -f2-)" + local metadef_install_type="$(grep -iw metadef_install_type "$install_info_old" | cut -d"=" -f2-)" + else + log "ERROR" "ERR_NO:0x0080;ERR_DES:Installation information no longer exists, please complete ${upgrade_install_info} or ${install_info_old}" + exit_uninstall_log 1 + fi + if [ "$is_docker_install" = "y" ]; then + metadef_install_path_param=$(concat_docker_install_path "${docker_root}" "${metadef_input_install_path}") + else + metadef_install_path_param="${metadef_input_install_path}" + fi + local upgrade_default_dir="$(dirname $upgrade_install_info)" + if [ ! -f "$upgrade_default_dir/script/run_metadef_uninstall.sh" ]; then + log "WARNING" "run_metadef_uninstall.sh not found." + return $? + fi + if [ "$1" = "uninstall" ]; then + chmod_start "$upgrade_default_dir" + new_echo "INFO" "uninstall ${metadef_install_path_param} ${metadef_install_type}" + log "INFO" "uninstall ${metadef_install_path_param} ${metadef_install_type}" + bash "$upgrade_default_dir/script/run_metadef_uninstall.sh" "uninstall" "${metadef_input_install_path}" "${metadef_install_type}" "${is_quiet}" \ + "${is_docker_install}" "${docker_root}" "${is_recreate_softlink}" + if [ $? -eq 0 ]; then + if [ "$is_remove_info_files" = "y" ]; then + test -f "$upgrade_install_info" && rm -f "$upgrade_install_info" + test -f "$upgrade_default_dir/version.info" && rm -f "$upgrade_default_dir/version.info" + fi + remove_dir_recursive "$install_top_path" "$upgrade_default_dir" + if [ $(id -u) -eq 0 ]; then + if [ "$uninstall" = "y" ] && [ -f "$install_info_old" ] && [ $(grep -c -i metadef_install_path_param "$install_info_old") -ne 0 ]; then + sed -i '/metadef_install_path_param=/Id' "$install_info_old" 2> /dev/null + sed -i '/metadef_install_type=/Id' "$install_info_old" 2> /dev/null + fi + fi + new_echo "INFO" "metadef package uninstalled successfully! Uninstallation takes effect immediately." + log "INFO" "metadef package uninstalled successfully! Uninstallation takes effect immediately." + log_operation "${operation}" "succeeded" + else + log "ERROR" "metadef package uninstall failed!" + log_operation "${operation}" "failed!" + exit_uninstall_log 1 + fi + fi + return $? +} + +save_user_files_to_log() { + if [ "$1" = "${default_dir}" ] && [ -s "$1" ]; then + local filenum=$(ls -lR "$1"|grep "^-"|wc -l) + local dirnum=$(ls -lR "$1"|grep "^d"|wc -l) + local totalnum=$(expr "${filenum}" + "${dirnum}") + if [ "$totalnum" -eq 2 ]; then + if [ -f "${install_info}" ] && [ -f "${default_dir}/version.info" ]; then + return 0 + fi + fi + if [ "$totalnum" -eq 1 ]; then + if [ -f "${install_info}" ] || [ -f "${default_dir}/version.info" ]; then + return 0 + fi + fi + log "INFO" "Some files generated by user are not cleared, if necessary, manually clear them, get details in $logfile" + fi + if [ -s "$1" ]; then + for file in $(ls -a "$1"); do + if [ -d "$1/$file" -a ! -L "$1/$file" ]; then + if [ "$file" != '.' ] && [ "$file" != '..' ]; then + echo "$1/$file" >> "$logfile" + save_user_files_to_log "$1/$file" + fi + else + echo "$1/$file" >> "$logfile" + fi + done + fi +} + +judgmentpath() { + . "${common_func_path}" + check_install_path_valid "${1}" + if [ $? -ne 0 ]; then + log "ERROR" "The metadef install_path ${1} is invalid, only characters in [a-z,A-Z,0-9,-,_] are supported!" + exit 1 + fi +} + +unique_mode() { + if [ ! -z "$g_param_check_flag" ]; then + log "ERROR" "ERR_NO:0x0004;ERR_DES:only support one type: full/run/docker/devel/upgrade/uninstall, operation failed!" + exit 1 + fi +} + +check_install_for_all() { + local mod_num="" + local other_mod_num="" + if [ "$input_install_for_all" = "y" ] && [ -d "$pkg_install_path" ]; then + mod_num="$(stat -c %a ${pkg_install_path})" + mod_num="$(check_chmod_length $mod_num)" + other_mod_num="$(expr substr $mod_num 3 1)" + if [ "${other_mod_num}" -ne 5 ] && [ "${other_mod_num}" -ne 7 ]; then + log "ERROR" "${pkg_install_path} permission is ${mod_num}, this permission does not support install_for_all param." + exit_install_log 1 + fi + fi +} + +pre_check() { + local check_shell_path="${curpath}/../bin/prereq_check.bash" + if [ ! -f "${check_shell_path}" ]; then + log "WARNING" "${check_shell_path} not exist." + return 0 + fi + if [ "x$is_quiet" = "xy" ]; then + bash "${check_shell_path}" --quiet + else + bash "${check_shell_path}" --no-quiet + fi +} + +uninstall_none_multi_version() { + if [ "$hetero_arch" = "y" ]; then + return + fi + local install_path="$1" + if [ "$pkg_is_multi_version" = "true" ] && [ ! -L "$install_path" ] && [ -d "$install_path" ]; then + if [ "$full_install" = "y" ] || [ "$run_install" = "y" ] || [ "$devel_install" = "y" ] || [ "$upgrade" = "y" ] || [ "$uninstall" = "y" ]; then + local path_version="$install_path/version.info" + local path_install="$install_path/ascend_install.info" + if [ -f "$path_version" ] && [ -f "$path_install" ] && [ -f "$install_path/script/uninstall.sh" ]; then + $install_path/script/uninstall.sh + fi + fi + fi +} + +migrate_user_assets_v2() { + if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" != "y" ]; then + get_package_last_installed_version_dir "last_installed_dir" "$pkg_install_path" "metadef" + if [ -n "$last_installed_dir" ]; then + last_installed_dir="$pkg_install_path/$last_installed_dir" + local current_installed_dir="${pkg_install_path}/$pkg_version_dir" + local data_dir="metadef/data/fusion_strategy" + if [ -d "$last_installed_dir/$data_dir/custom" ] && [ "x$(ls -A $last_installed_dir/$data_dir/custom)" != "x" ]; then + mkdir -p "$current_installed_dir/$data_dir" + log "INFO" "cp -rpf $last_installed_dir/$data_dir/custom $current_installed_dir/$data_dir" + cp -rpf "$last_installed_dir/$data_dir/custom" "$current_installed_dir/$data_dir" + fi + fi + fi +} + +#################################################################################################### +runfilename=$(expr substr "$1" 5 $(expr ${#1} - 4)) + +full_install=n +run_install=n +docker_install=n +devel_install=n +uninstall=n +upgrade=n +installmode="" +chip_flag=n +chipmode="all" +feature_flag=n +featuremode="all" +pylocal=n +install_path_cmd="--install-path" +input_install_path="" +install_top_path="" +in_install_for_all="" +docker_root="" +setenv="" +input_path_flag=n +input_install_for_all=n +is_docker_install=n +input_pre_check=n +input_setenv=n +uninstall_path_cmd="--uninstall" +uninstall_path_param="" +upgrade_path_cmd="--upgrade" +upgrade_path_param="" +docker_cmd="--docker" +is_quiet=n +check=n +install_path_param="" +g_param_check_flag="" +hetero_arch=n + +if [ $(id -u) -eq 0 ]; then + input_install_for_all=y + input_install_path="$default_root_dir" + install_path_param="$default_root_dir" + in_install_for_all="--install_for_all" +else + input_install_path="$default_normal_dir" + install_path_param="$default_normal_dir" +fi + +create_log_folder +change_log_mode + +#################################################################################################### +if [ "$#" = "1" ] || [ "$#" = "2" ]; then + log "ERROR" "ERR_NO:0x0004;ERR_DES:Unrecognized parameters. Try './xxx.run --help for more information.'" + exit 1 +fi + +i=0 +while true +do + if [ "x$1" = "x" ]; then + break + fi + if [ "$(expr substr "$1" 1 2)" = "--" ]; then + i=$(expr $i + 1) + fi + if [ $i -gt 2 ]; then + break + fi + shift 1 +done + +all_parma="$*" + +################################################################################# +while true +do + case "$1" in + --help | -h) + param_usage + exit 0 + ;; + --run) + unique_mode + g_param_check_flag="True" + run_install=y + installmode="run" + shift + ;; + --full) + unique_mode + g_param_check_flag="True" + full_install=y + installmode="full" + shift + ;; + --docker) + unique_mode + g_param_check_flag="True" + docker_install=y + installmode="docker" + shift + ;; + --devel) + unique_mode + g_param_check_flag="True" + devel_install=y + installmode="devel" + shift + ;; + --install-path=*) + temp_path=$(echo "$1" | cut -d"=" -f2-) + judgmentpath "${temp_path}" + slashes_num=$(echo "${temp_path}" | grep -o '/' | wc -l) + if [ "$slashes_num" -gt 1 ]; then + input_install_path=$(echo "${temp_path}" | sed "s/\/*$//g") + else + input_install_path="${temp_path}" + fi + input_path_flag=y + shift + ;; + --chip=*) + chip_flag=y + shift + ;; + --feature=*) + featuremode=$(echo "$1" | cut -d"=" -f2-) + feature_flag=y + shift + ;; + --install-for-all) + input_install_for_all=y + in_install_for_all="--install_for_all" + shift + ;; + --docker-root=*) + temp_path=$(echo "$1" | cut -d"=" -f2-) + judgmentpath "${temp_path}" + slashes_num=$(echo "${temp_path}" | grep -o '/' | wc -l) + if [ "$slashes_num" -gt 1 ]; then + docker_root=$(echo "${temp_path}" | sed "s/\/*$//g") + else + docker_root="${temp_path}" + fi + is_docker_install=y + check_docker_path "${docker_root}" + shift + ;; + --pre-check) + input_pre_check=y + shift + ;; + --setenv) + input_setenv=y + setenv="--setenv" + shift + ;; + --uninstall) + unique_mode + g_param_check_flag="True" + uninstall=y + shift + ;; + --upgrade) + unique_mode + g_param_check_flag="True" + upgrade=y + shift + ;; + --quiet) + is_quiet=y + shift + ;; + --pylocal) + pylocal=y + shift + ;; + --extract=*) + shift; + ;; + --keep) + shift; + ;; + --check) + check=y + shift + ;; + --version) + get_version_in_runpkg + version=y + exit 0 + ;; + -*) + log "ERROR" "ERR_NO:0x0004;ERR_DES: Unsupported parameters : $1" + param_usage + exit 0 + ;; + *) + break + ;; + esac +done + +###################### 检查参数冲突 ################### +if [ "${is_quiet}" = "y" ]; then + if [ "${upgrade}" = "y" ] || [ "${full_install}" = "y" ] || [ "${run_install}" = "y" ] || [ "${devel_install}" = "y" ] || [ "${uninstall}" = "y" ]; then + is_quiet=y + elif [ "${input_pre_check}" = "y" ] || [ "${check}" = "y" ]; then + is_quiet=y + else + log "ERROR" "'--quiet' is not supported to used by this way, please use with '--full', '--devel', '--run', '--upgrade', '--uninstall', '--check' or '--pre-check'" + exit 1 + fi +fi + +# 检查chip参数是否冲突 +if [ "${chip_flag}" = "y" ] && [ "${uninstall}" = "y" ]; then + log "ERROR" "'--chip' is not supported to used by this way, please use with '--full', '--devel', '--run', '--upgrade'" + exit 1 +fi + +# 检查feature参数是否冲突 +if [ "${feature_flag}" = "y" ] && [ "${uninstall}" = "y" ]; then + log "ERROR" "'--feature' is not supported to used by this way, please use with '--full', '--devel', '--run', '--upgrade'" + exit 1 +fi + +if [ "${pylocal}" = "y" ]; then + if [ "${upgrade}" != "y" ] && [ "${full_install}" != "y" ] && [ "${run_install}" != "y" ] && [ "${devel_install}" != "y" ]; then + log "ERROR" "'--pylocal' is not supported to used by this way, please use with '--full', '--devel', '--run' or '--upgrade'." + exit 1 + fi +fi + +# 卸载参数只支持单独使用 +if [ "$uninstall" = "y" ]; then + if [ "$upgrade" = "y" ] || [ "$full_install" = "y" ] || [ "$run_install" = "y" ] || [ "$devel_install" = "y" ] || [ "$docker_install" = "y" ] || [ "$check" = "y" ] || [ "$input_pre_check" = "y" ]; then + log "ERROR" "ERR_NO:0x0004;ERR_DES:Unsupported parameters, operation failed." + exit 1 + fi +fi + +if [ "$docker_install" = "y" ]; then + log "ERROR" "ERR_NO:0x0004;ERR_DES:Unsupported parameters, operation failed." + log "INFO" "--docker not uesd in metadef" + exit 1 +fi + +# 检查必选参数 +if [ "${upgrade}" = "n" ] && [ "${full_install}" = "n" ] && [ "${run_install}" = "n" ] && [ "${devel_install}" = "n" ] && [ "${uninstall}" = "n" ] && [ "${input_pre_check}" = "n" ] && [ "${check}" = "n" ]; then + log "ERROR" "ERR_NO:0x0004;One of parameters '--full', '--devel', '--run', '--upgrade', '--uninstall', '--check' or '--pre-check' must be used." + exit 1 +fi + +if [ "$featuremode" != "all" ]; then + contain_feature "ret" "$featuremode" "$curpath/filelist.csv" + if [ "$ret" = "false" ]; then + log "WARNING" "metadef package doesn't contain features $featuremode, skip installation." + exit 0 + fi +fi + +####################################################### +is_multi_version_pkg "pkg_is_multi_version" "$pkg_version_path" +get_version_dir "pkg_version_dir" "$pkg_version_path" + +if [ "$full_install" = "y" ] || [ "$run_install" = "y" ] || [ "$devel_install" = "y" ] || [ "$upgrade" = "y" ] || [ "$uninstall" = "y" ]; then + input_install_path=$(relative_path_to_absolute_path "${input_install_path}") + get_install_path + + if [ "$(is_same_arch_pkg_installed)" = "y" ]; then + hetero_arch="y" + fi + if [ "$upgrade" = "y" ] || [ "$uninstall" = "y" ]; then + hetero_arch_pkg_installed="$(is_hetero_arch_pkg_installed)" + if [ "$hetero_arch_pkg_installed" = "installed-hetero" ]; then + hetero_arch="y" + elif [ "$hetero_arch_pkg_installed" = "installed-normal" ]; then + hetero_arch="n" + elif [ "$hetero_arch_pkg_installed" = "installed-hetero-to-be-upgraded" ]; then + hetero_arch="y" + elif [ "$hetero_arch_pkg_installed" = "installed-normal-to-be-upgraded" ]; then + hetero_arch="n" + elif [ "$hetero_arch_pkg_installed" = "no" ]; then + log "ERROR" "ERR_NO:0x0080;ERR_DES:Runfile is not installed in ${input_install_path}, operation failed!" + exit 1 + fi + fi + export hetero_arch + + install_top_path="$(dirname $input_install_path)" + install_path_param="${input_install_path}" + if [ "$hetero_arch" = "y" ]; then + if [ "$pkg_is_multi_version" = "true" ]; then + install_path_param="$install_path_param/$pkg_version_dir/$arch_scripts_path" + else + install_path_param="$install_path_param/$arch_scripts_path" + fi + fi +fi + +if [ "$is_docker_install" = "y" ]; then + pkg_install_path=$(concat_docker_install_path "${docker_root}" "${install_path_param}") +else + pkg_install_path="${install_path_param}" +fi + +if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" != "y" ]; then + default_dir="${pkg_install_path}/$pkg_version_dir/metadef" +else + default_dir="${pkg_install_path}/metadef" +fi +install_info="${default_dir}/ascend_install.info" + +if [ "$uninstall" = "y" ]; then + start_uninstall_log +else + start_install_log +fi + +if [ "$hetero_arch" = "y" ]; then + log "INFO" "package is running in hetero arch mode!" +fi + +# 执行预检查 +if [ "$input_pre_check" = "y" ]; then + log "INFO" "metadef do pre check started." + pre_check + if [ $? -ne 0 ]; then + log "WARNING" "metadef do pre check failed." + else + log "INFO" "metadef do pre check finished." + fi + if [ "$full_install" = "n" ] && [ "$run_install" = "n" ] && [ "$devel_install" = "n" ] && [ "$upgrade" = "n" ]; then + exit_install_log 0 + fi +fi + +# 版本兼容性检查 +if [ "$check" = "y" ]; then + ver_check + if [ -z "$pkg_version_dir" ]; then + preinstall_check --install-path="$install_path_param" --script-dir="$curpath" --package="metadef" --logfile="$logfile" --docker-root="$docker_root" + if [ $? -ne 0 ]; then + exit_install_log 1 + else + log "INFO" "version compatibility check successfully!" + fi + fi + if [ "$full_install" = "n" ] && [ "$run_install" = "n" ] && [ "$devel_install" = "n" ] && [ "$upgrade" = "n" ]; then + exit_install_log 0 + fi +elif [ "$full_install" = "y" ] || [ "$run_install" = "y" ] || [ "$devel_install" = "y" ] || [ "$upgrade" = "y" ]; then + ver_check + if [ -z "$pkg_version_dir" ]; then + preinstall_process --install-path="$install_path_param" --script-dir="$curpath" --package="metadef" --logfile="$logfile" --docker-root="$docker_root" + if [ $? -ne 0 ]; then + exit_install_log 1 + else + log "INFO" "version compatibility check successfully!" + fi + fi +fi + +################################################################## +# 安装升级运行态时, 1/2包必须已安装, 且指定的用户必须存在且与1/2包同属组 +if [ "$input_install_for_all" = "n" ]; then + if [ "$run_install" = "y" ] || [ "$full_install" = "y" ] || [ "$devel_install" = "y" ]; then + confirm=n + if [ ! -f "$install_info_old" ]; then + log "WARNING" "driver and firmware is not exists, please install first." + confirm=y + elif [ $(grep -c -i "Driver" "${install_info_old}") -eq 0 ]; then + log "WARNING" "driver is not exists, please install first." + confirm=y + elif [ $(grep -c -i "Firmware" "${install_info_old}") -eq 0 ]; then + log "WARNING" "firmware is not exists, please install first. (docker scenes is not need)" + confirm=y + elif [ -f "${install_info_old}" ]; then + usergroup_base=$(grep -i usergroup= "${install_info_old}" | cut -d"=" -f2-) + check_group "${usergroup_base}" "${username}" + if [ $? -ne 0 ]; then + log "ERROR" "ERR_NO:0x0093;ERR_DES:User is not belong to the dirver or firmware's installed usergroup! Please add the user (${username}) to the group (${usergroup_base})." + confirm=y + exit_install_log 1 + fi + fi + fi +fi + +uninstall_none_multi_version "$pkg_install_path/metadef" +check_install_for_all +create_default_install_dir_for_common_user +log_base_version +if [ "$upgrade" != "y" ] || [ "$hetero_arch_pkg_installed" != "installed-hetero-to-be-upgraded" ]; then + is_valid_path +fi +[ "$hetero_arch" = "y" ] && replace_filelist + +if [ "$full_install" = "y" ] || [ "$run_install" = "y" ] || [ "$devel_install" = "y" ]; then + create_default_dir +fi + +# 环境上是否已安装过本包 +version_installed="$(get_version_installed)" +if [ "x$version_installed" != "x" -a "$version_installed" != "none" ] || [ -f "${install_info}" ]; then + # 卸载场景 + if [ "$uninstall" = "y" ]; then + unchattr_files + uninstall_run "uninstall" "y" "y" + if [ -d "${default_dir}/site-packages" ]; then + rm -rf "${default_dir}/site-packages" + fi + save_user_files_to_log "$default_dir" + save_user_files_to_log "$(dirname $default_dir)/atc" + save_user_files_to_log "$(dirname $default_dir)/fwkacllib" + exit_uninstall_log 0 + # 升级场景 + elif [ "$upgrade" = "y" ]; then + if [ -n "$pkg_version_dir" ]; then + if [ "$hetero_arch" = "y" ]; then + get_package_upgrade_install_info_hetero "upgrade_install_info" + else + get_package_upgrade_install_info "upgrade_install_info" "$pkg_install_path" "metadef" + fi + if [ -z "$upgrade_install_info" ]; then + log "ERROR" "Can not find softlink for this package in latest directory, upgrade failed" + log_operation "Upgrade" "failed" + exit_install_log 1 + elif [ "$(realpath $upgrade_install_info)" != "$(realpath $install_info)" ]; then + uninstall_run "uninstall" "n" "y" "$upgrade_install_info" + fi + fi + unchattr_files + uninstall_run "uninstall" "n" "n" + save_user_files_to_log "$default_dir" + save_user_files_to_log "$(dirname $default_dir)/atc" + save_user_files_to_log "$(dirname $default_dir)/fwkacllib" + upgrade_run "upgrade" + exit_install_log 0 + # 安装场景 + elif [ "$run_install" = "y" ] || [ "$full_install" = "y" ] || [ "$devel_install" = "y" ]; then + version_of_package=$(get_version_in_runpkg) + if [ "$is_quiet" = "n" ]; then + log "INFO" "metadef package has been installed on the path ${pkg_install_path}, the version is ${version_installed}, and the version of this package is ${version_of_package}, do you want to continue? [y/n]" + while true + do + read yn + if test "$yn" = n; then + log "INFO" "stop installation!" + exit_install_log 0 + elif test "$yn" = y; then + break + else + log "ERROR" "ERR_NO:0x0002;ERR_DES:input error, please input again!" + fi + done + fi + unchattr_files + uninstall_run "uninstall" "n" "n" + save_user_files_to_log "$default_dir" + save_user_files_to_log "$(dirname $default_dir)/atc" + save_user_files_to_log "$(dirname $default_dir)/fwkacllib" + install_run "install" + exit_install_log 0 + fi +else + # 卸载场景 + if [ "$uninstall" = "y" ]; then + if [ -d "$default_dir" ]; then + log "ERROR" "The current user does not have the required permission to uninstall $default_dir, uninstall failed" + log_operation "Uninstall" "failed" + exit_uninstall_log 1 + else + log "ERROR" "ERR_NO:0x0080;ERR_DES:Runfile is not installed in ${pkg_install_path}, uninstall failed" + log_operation "Uninstall" "failed" + exit_uninstall_log 1 + fi + # 升级场景 + elif [ "$upgrade" = "y" ]; then + if [ -z "$pkg_version_dir" ]; then + if [ -d "$default_dir" ]; then + log "ERROR" "The current user does not have the required permission to uninstall $default_dir, upgrade failed" + log_operation "Upgrade" "failed" + exit_install_log 1 + else + log "ERROR" "ERR_NO:0x0080;ERR_DES:Runfile is not installed in ${pkg_install_path}, upgrade failed" + log_operation "Upgrade" "failed" + exit_install_log 1 + fi + else + if [ "$hetero_arch" = "y" ]; then + get_package_upgrade_install_info_hetero "upgrade_install_info" + else + get_package_upgrade_install_info "upgrade_install_info" "$pkg_install_path" "metadef" + fi + if [ -f "$upgrade_install_info" ]; then + create_default_dir && cp "$upgrade_install_info" "$install_info" + migrate_user_assets_v2 + [ "$hetero_arch" = "y" ] && update_install_info_hetero "$install_info" "$pkg_version_dir" + uninstall_run "uninstall" "n" "y" "$upgrade_install_info" + upgrade_run "upgrade" + exit_install_log 0 + else + log "ERROR" "ERR_NO:0x0080;ERR_DES:Runfile is not installed in ${pkg_install_path}, upgrade failed" + log_operation "Upgrade" "failed" + exit_install_log 1 + fi + fi + # 安装场景 + elif [ "$run_install" = "y" ] || [ "$full_install" = "y" ] || [ "$devel_install" = "y" ]; then + install_run "install" + exit_install_log 0 + fi +fi \ No newline at end of file diff --git a/scripts/package/metadef/scripts/metadef_func.sh b/scripts/package/metadef/scripts/metadef_func.sh new file mode 100644 index 0000000000000000000000000000000000000000..0a446b2cc83d5d7942c9886c4d886ada800231bd --- /dev/null +++ b/scripts/package/metadef/scripts/metadef_func.sh @@ -0,0 +1,212 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +get_pkg_arch_name() { + local scene_info="$curpath/../scene.info" + if [ ! -f "$scene_info" ]; then + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + echo "[metadef] [$cur_date] [ERROR]: $scene_info file cannot be found!" + exit 1 + fi + local arch="$(grep -iw arch "$scene_info" | cut -d"=" -f2- | awk '{print tolower($0)}')" + if [ -z "$arch" ]; then + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + echo "[metadef] [$cur_date] [ERROR]: var arch cannot be found in file $scene_info!" + exit 1 + fi + echo $arch +} + +get_installed_pkg_arch_name() { + if [ "$pkg_is_multi_version" = "true" ]; then + local scene_info="$docker_root$input_install_path/$pkg_version_dir/metadef/scene.info" + else + local scene_info="$docker_root$input_install_path/metadef/scene.info" + fi + if [ ! -f "$scene_info" ]; then + return + fi + local arch="$(grep -iw arch "$scene_info" | cut -d"=" -f2- | awk '{print tolower($0)}')" + echo $arch +} + +get_os_arch_name() { + uname -m 2>&1 | awk '{print tolower($0)}' +} + +get_hetero_arch_name() { + if [ "x$(get_pkg_arch_name)" = "xx86_64" ]; then + echo aarch64 + else + echo x86_64 + fi +} + +if [ "$(get_pkg_arch_name)" = "$(get_os_arch_name)" ]; then + is_pkg_hetero_arch="n" +else + is_pkg_hetero_arch="y" +fi + +arch_linux_path="$(get_pkg_arch_name)-linux" +arch_scripts_path="$arch_linux_path/hetero-arch-scripts" +arch_linux_path_os="$(get_os_arch_name)-linux" +arch_linux_path_hetero="$(get_hetero_arch_name)-linux" +arch_scripts_path_hetero="$arch_linux_path_hetero/hetero-arch-scripts" + +is_same_arch_pkg_installed() { + if [ "$pkg_is_multi_version" = "true" ]; then + local linux_path="$docker_root$input_install_path/$pkg_version_dir/$arch_linux_path_os" + else + local linux_path="$docker_root$input_install_path/$arch_linux_path_os" + fi + if [ "$is_pkg_hetero_arch" = "y" ] && [ -d "$linux_path" ]; then + echo "y" + else + echo "n" + fi +} + +get_package_upgrade_install_info_hetero() { + local _outvar="$1" + local path_latest="$docker_root$input_install_path/latest" + local path_hetero="$docker_root$input_install_path/latest/$arch_scripts_path" + if [ -d "$path_latest" ] && [ -d "$path_hetero" ]; then + local install_info=$(find "$path_hetero" -type f -name 'ascend_install.info' | grep 'metadef/ascend_install.info') + if [ -n "$install_info" ]; then + install_info="$(realpath $install_info)" + eval "${_outvar}=\"$install_info\"" + return + fi + fi + eval "${_outvar}=\"\"" +} + +is_hetero_arch_pkg_installed() { + if [ "$is_pkg_hetero_arch" = "y" ]; then + if [ "$pkg_is_multi_version" = "true" ]; then + local path_version="$docker_root$input_install_path/$pkg_version_dir/$arch_scripts_path/metadef/version.info" + local path_install="$docker_root$input_install_path/$pkg_version_dir/$arch_scripts_path/metadef/ascend_install.info" + else + local path_version="$docker_root$input_install_path/$arch_scripts_path/metadef/version.info" + local path_install="$docker_root$input_install_path/$arch_scripts_path/metadef/ascend_install.info" + fi + if [ -f "$path_version" ] && [ -f "$path_install" ]; then + echo "installed-hetero" + return + fi + + if [ "$pkg_is_multi_version" = "true" ]; then + local path_version="$docker_root$input_install_path/$pkg_version_dir/metadef/version.info" + local path_install="$docker_root$input_install_path/$pkg_version_dir/metadef/ascend_install.info" + else + local path_version="$docker_root$input_install_path/metadef/version.info" + local path_install="$docker_root$input_install_path/metadef/ascend_install.info" + fi + if [ -f "$path_version" ] && [ -f "$path_install" ] && [ "$(get_installed_pkg_arch_name)" = "$(get_pkg_arch_name)" ]; then + echo "installed-normal" + return + fi + + if [ "$pkg_is_multi_version" = "true" ]; then + get_package_upgrade_install_info_hetero "ascend_install_info" + if [ -f "${ascend_install_info}" ]; then + echo "installed-hetero-to-be-upgraded" + return + else + get_package_upgrade_install_info "ascend_install_info" "$docker_root$input_install_path" "metadef" + if [ -f "${ascend_install_info}" ]; then + echo "installed-normal-to-be-upgraded" + return + fi + fi + fi + + echo "no" + else + echo "NA" + fi +} + +update_install_info_hetero() { + local install_info=$1 + local pkg_version_dir=$2 + if [ -f "$install_info" ]; then + chmod u+w "$(dirname $install_info)" "$install_info" + local new_install_path="$(grep -iw METADEF_Install_Path_Param $install_info)" + local new_install_path="$(echo $new_install_path | awk -v version=$pkg_version_dir 'BEGIN{FS=OFS="/"} {$(NF-2)=version; print}')" + sed -i -e "s:METADEF_Install_Path_Param=.*:$new_install_path:" "$install_info" + fi +} + +replace_filelist() { + local curpath=$(dirname $(readlink -f "$0")) + cp -p $curpath/filelist.csv $curpath/filelist.csv.bak && awk -v arch_prefix="$arch_linux_path" 'BEGIN { + FS=OFS="," + pat="^"arch_prefix + } + + function in_pkg_black_list() { + relative_install_path = $4 + if (relative_install_path ~ /^metadef\/python/) { return 1 } + return 0 + } + + function format_softlink(links) { + split(links, arr, ";") + ret = "" + for (i in arr) { + if (arr[i] ~ pat) { arr[i] = "../../" arr[i] } + ret = ret ";" arr[i] + } + sub("^;", "", ret) + return ret + } + + { + if (in_pkg_black_list()) { next } + if ($4 ~ pat) { + if ($4 ~ pat"/python") { $15 = "NA" } + $4 = "../../" $4; + } + $9 = format_softlink($9) + print + }' $curpath/filelist.csv.bak > $curpath/filelist.csv +} + +get_dir_mod() { + local path="$1" + stat -c %a "$path" +} + +remove_dir_recursive() { + local dir_start="$1" + local dir_end="$2" + if [ "$dir_end" = "$dir_start" ]; then + return 0 + fi + if [ ! -e "$dir_end" ]; then + return 0 + fi + if [ "x$(ls -A $dir_end 2>&1)" != "x" ]; then + return 0 + fi + local up_dir="$(dirname $dir_end)" + local oldmod="$(get_dir_mod $up_dir)" + chmod u+w "$up_dir" + [ -n "$dir_end" ] && rm -rf "$dir_end" + if [ $? -ne 0 ]; then + chmod "$oldmod" "$up_dir" + return 1 + fi + chmod "$oldmod" "$up_dir" + remove_dir_recursive "$dir_start" "$up_dir" +} \ No newline at end of file diff --git a/scripts/package/metadef/scripts/prereq_check.bash b/scripts/package/metadef/scripts/prereq_check.bash new file mode 100644 index 0000000000000000000000000000000000000000..c99d4de46965c62e9d993350c4c7d7bcb6345107 --- /dev/null +++ b/scripts/package/metadef/scripts/prereq_check.bash @@ -0,0 +1,84 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +MIN_PIP_VERSION=19 +PYTHON_VERSION=3.7.5 + +IS_QUIET=y +if [ "x$1" = "x--no-quiet" ]; then + IS_QUIET=n +fi + +log() { + local content=$(echo "$@" | cut -d" " -f2-) + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + echo -e "[metadef] [$cur_date] [$1]: $content" +} + +input_check() { + [ "${IS_QUIET}" = y ] && return + log "INFO" "\033[32mDo you want to continue? [y/n]\033[0m" + while true; do + read yn + if [ "$yn" = n ]; then + exit 1 + elif [ "$yn" = y ]; then + break + else + log "ERROR" "ERR_NO:0x0002;ERR_DES:input error, please input again!" + fi + done +} + +version_lt() { + test $(echo "$@" | tr " " "\n" | sort -rV | head -n 1) != "$1" +} + +check_py_module_depends() { + local module_name="$1" + local module_version="$2" + local depends_message="$3" + local required_message=$(eval echo "$4") + pip3 show "$module_name" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "WARNING" "\033[33mpython module '$module_name' is not installed$required_message$depends_message\033[0m" + elif [ "x$module_version" != "x" ]; then + local version=$(pip3 show "$module_name" 2> /dev/null | grep -iw ^version | cut -d' ' -f2) + if [ "x$version" = "x" ]; then + log "WARNING" "\033[33mcannot get module '$module_name' version\033[0m" + elif version_lt "$version" "$module_version"; then + log "WARNING" "\033[33mpython module '$module_name' version ${version} is lower than ${module_version}$required_message\033[0m" + fi + fi +} + +which pip3 > /dev/null 2>&1 +if [ $? -eq 0 ]; then + pip3_version="$(pip3 --version 2>/dev/null | head -n 1)" + pip3_version=$(expr "$pip3_version" : 'pip \([0-9]\+\(\.[0-9]\+\)\+\)') + if [ "x$pip3_version" = "x" ]; then + log "WARNING" "\033[33mcannot get pip3 version\033[0m" + input_check + elif version_lt "$pip3_version" "$MIN_PIP_VERSION"; then + log "WARNING" "\033[33mpip3 version ${pip3_version} is lower than ${MIN_PIP_VERSION}.x.x\033[0m" + input_check + fi +else + log "WARNING" "\033[33mpip3 is not found.\033[0m" +fi + +curpath="$(dirname ${BASH_SOURCE:-$0})" +install_dir="$(realpath $curpath/..)" +common_interface=$(realpath $install_dir/script*/common_interface.bash) +if [ -f "$common_interface" ]; then + . "$common_interface" + py_version_check +fi diff --git a/scripts/package/metadef/scripts/prereq_check.csh b/scripts/package/metadef/scripts/prereq_check.csh new file mode 100644 index 0000000000000000000000000000000000000000..b544a0ae61c747cb122dc8fbf941b6b15ba25e14 --- /dev/null +++ b/scripts/package/metadef/scripts/prereq_check.csh @@ -0,0 +1,28 @@ +#!/usr/bin/env csh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +set MIN_PIP_VERSION=19 +set PYTHON_VERSION=3.7.5 + +set version=`pip3 --version | cut -d" " -f2 | cut -d"." -f1` +if (${version} < ${MIN_PIP_VERSION}) then + echo "pip3 version is lower than ${MIN_PIP_VERSION}.x.x" +endif + +set python_version=`python3 --version | cut -d" " -f2` +foreach num (1 2 3) + set version_num=`echo ${python_version} | cut -d"." -f${num}` + set min_version_num=`echo ${PYTHON_VERSION} | cut -d"." -f${num}` + if (${version_num} != ${min_version_num}) then + echo "python version ${python_version} is not equals ${PYTHON_VERSION}." + break + endif +end diff --git a/scripts/package/metadef/scripts/prereq_check.fish b/scripts/package/metadef/scripts/prereq_check.fish new file mode 100644 index 0000000000000000000000000000000000000000..d49551677986111bd5f48a18270d9994401f67e3 --- /dev/null +++ b/scripts/package/metadef/scripts/prereq_check.fish @@ -0,0 +1,28 @@ +#!/usr/bin/env fish +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +set -x MIN_PIP_VERSION 19 +set -x PYTHON_VERSION 3.7.5 + +set -lx version (pip3 --version | cut -d" " -f2 | cut -d"." -f1) +if test {$version} -lt {$MIN_PIP_VERSION} + echo "pip3 version is lower than $MIN_PIP_VERSION.x.x" +end + +set -lx python_version (python3 --version | cut -d" " -f2) +for num in (seq 1 3) + set -lx version_num (echo {$python_version} | cut -d"." -f{$num}) + set -lx min_version_num (echo {$PYTHON_VERSION} | cut -d"." -f{$num}) + if test {$version_num} -ne {$min_version_num} + echo "python version $python_version is not equals $PYTHON_VERSION." + break + end +end diff --git a/scripts/package/metadef/scripts/run_metadef_install.sh b/scripts/package/metadef/scripts/run_metadef_install.sh new file mode 100644 index 0000000000000000000000000000000000000000..91bd921b9e2707caffc39a2901ef8af7028f6fd7 --- /dev/null +++ b/scripts/package/metadef/scripts/run_metadef_install.sh @@ -0,0 +1,165 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +username="$(id -un)" +usergroup="$(id -gn)" +is_quiet=n +pylocal=n +in_install_for_all=n +setenv_flag=n +docker_root="" +sourcedir="$PWD/metadef" +curpath=$(dirname $(readlink -f "$0")) +common_func_path="${curpath}/common_func.inc" +pkg_version_path="${curpath}/../../version.info" +chip_type="all" +feature_type="all" + +. "${common_func_path}" + +if [ "$1" ]; then + input_install_dir="${2}" + common_parse_type="${3}" + is_quiet="${4}" + pylocal="${5}" + setenv_flag="${6}" + docker_root="${7}" + in_install_for_all="${8}" +fi + +if [ "x${docker_root}" != "x" ]; then + common_parse_dir="${docker_root}${input_install_dir}" +else + common_parse_dir="${input_install_dir}" +fi + +get_version "pkg_version" "$pkg_version_path" +is_multi_version_pkg "pkg_is_multi_version" "$pkg_version_path" +if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" != "y" ]; then + get_version_dir "pkg_version_dir" "$pkg_version_path" + common_parse_dir="$common_parse_dir/$pkg_version_dir" +fi + +if [ $(id -u) -ne 0 ]; then + log_dir="${HOME}/var/log/ascend_seclog" +else + log_dir="/var/log/ascend_seclog" +fi +logfile="${log_dir}/ascend_install.log" + +get_install_param() { + local _key="$1" + local _file="$2" + local _param="" + + if [ ! -f "${_file}" ]; then + exit 1 + fi + local install_info_key_array="METADEF_Install_Type METADEF_Chip_Type METADEF_Feature_Type METADEF_UserName METADEF_UserGroup METADEF_Install_Path_Param METADEF_Arch_Linux_Path METADEF_Hetero_Arch_Flag" + for key_param in ${install_info_key_array}; do + if [ "${key_param}" = "${_key}" ]; then + _param=$(grep -i "${_key}=" "${_file}" | cut -d"=" -f2-) + break + fi + done + echo "${_param}" +} + +install_info="${common_parse_dir}/metadef/ascend_install.info" +if [ -f "$install_info" ]; then + chip_type=$(get_install_param "METADEF_Chip_Type" "${install_info}") + feature_type=$(get_install_param "METADEF_Feature_Type" "${install_info}") + hetero_arch=$(get_install_param "METADEF_Hetero_Arch_Flag" "${install_info}") +fi + +# 写日志 +log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + local log_type="$1" + shift + if [ "$log_type" = "INFO" -o "$log_type" = "WARNING" -o "$log_type" = "ERROR" ]; then + echo -e "[metadef] [$cur_date] [$log_type]: $*" + else + echo "[metadef] [$cur_date] [$log_type]: $*" 1> /dev/null + fi + echo "[metadef] [$cur_date] [$log_type]: $*" >> "$logfile" +} + +# 静默模式日志打印 +new_echo() { + local log_type="$1" + local log_msg="$2" + if [ "${is_quiet}" = "n" ]; then + echo "${log_type}" "${log_msg}" 1> /dev/null + fi +} + +output_progress() { + new_echo "INFO" "install upgradePercentage:$1%" + log "INFO" "install upgradePercentage:$1%" +} + +create_latest_linux_softlink() { + if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" = "y" ]; then + local linux_path="$(realpath $common_parse_dir/..)" + local arch_path="$(basename $linux_path)" + local latest_path="$(realpath $linux_path/../..)/latest" + if [ -d "$latest_path" ]; then + if [ ! -e "$latest_path/$arch_path" ] || [ -L "$latest_path/$arch_path" ]; then + ln -srfn "$linux_path" "$latest_path" + fi + fi + fi +} + +########################################################################## +log "INFO" "step into run_metadef_install.sh ......" +log "INFO" "install target dir $common_parse_dir, type $common_parse_type." + +if [ ! -d "$common_parse_dir" ]; then + log "ERROR" "ERR_NO:0x0001;ERR_DES:path $common_parse_dir is not exist." + exit 1 +fi + +new_install() { + if [ ! -d "${sourcedir}" ]; then + log "INFO" "no need to install metadef files." + return 0 + fi + output_progress 10 + + local setenv_option="" + if [ "${setenv_flag}" = y ]; then + setenv_option="--setenv" + fi + + # 执行安装 + custom_options="--custom-options=--common-parse-dir=$common_parse_dir,--logfile=$logfile,--stage=install,--quiet=$is_quiet,--pylocal=$pylocal,--hetero-arch=$hetero_arch" + sh "$curpath/install_common_parser.sh" --package="metadef" --install --username="$username" --usergroup="$usergroup" --set-cann-uninstall \ + --version=$pkg_version --version-dir=$pkg_version_dir \ + $setenv_option $in_install_for_all --docker-root="$docker_root" --chip="$chip_type" --feature="$feature_type" \ + $custom_options "$common_parse_type" "$input_install_dir" "$curpath/filelist.csv" + if [ $? -ne 0 ]; then + log "ERROR" "ERR_NO:0x0085;ERR_DES:failed to install package." + return 1 + fi + + create_latest_linux_softlink + return 0 +} + +new_install +if [ $? -ne 0 ]; then + exit 1 +fi + +output_progress 100 +exit 0 diff --git a/scripts/package/metadef/scripts/run_metadef_uninstall.sh b/scripts/package/metadef/scripts/run_metadef_uninstall.sh new file mode 100644 index 0000000000000000000000000000000000000000..e9a5e50f2763c7db624654770d319de8268be9d6 --- /dev/null +++ b/scripts/package/metadef/scripts/run_metadef_uninstall.sh @@ -0,0 +1,164 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +username="$(id -un)" +usergroup="$(id -gn)" +is_quiet=n +curpath=$(dirname $(readlink -f "$0")) +common_func_path="${curpath}/common_func.inc" +pkg_version_path="${curpath}/../version.info" + +. "${common_func_path}" + +if [ "$1" ]; then + input_install_dir="${2}" + common_parse_type="${3}" + is_quiet="${4}" + is_docker_install="${5}" # 兼容跨版本调用保留参数 + docker_root="${6}" + is_recreate_softlink="${7}" +fi + +if [ "${is_recreate_softlink}" = "y" ]; then + recreate_softlink_option="--recreate-softlink" +else + recreate_softlink_option="" +fi + +if [ "x${docker_root}" != "x" ]; then + common_parse_dir="${docker_root}${input_install_dir}" +else + common_parse_dir="${input_install_dir}" +fi + +get_version "pkg_version" "$pkg_version_path" +is_multi_version_pkg "pkg_is_multi_version" "$pkg_version_path" +if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" != "y" ]; then + get_version_dir "pkg_version_dir" "$pkg_version_path" + common_parse_dir="$common_parse_dir/$pkg_version_dir" +fi + +if [ $(id -u) -ne 0 ]; then + log_dir="${HOME}/var/log/ascend_seclog" +else + log_dir="/var/log/ascend_seclog" +fi +logfile="${log_dir}/ascend_install.log" + +SOURCE_INSTALL_COMMON_PARSER_FILE="${common_parse_dir}/metadef/script/install_common_parser.sh" +SOURCE_FILELIST_FILE="${common_parse_dir}/metadef/script/filelist.csv" + +get_install_param() { + local _key="$1" + local _file="$2" + local _param="" + + if [ ! -f "${_file}" ]; then + exit 1 + fi + local install_info_key_array="METADEF_Install_Type METADEF_Feature_Type METADEF_UserName METADEF_UserGroup METADEF_Install_Path_Param METADEF_Arch_Linux_Path METADEF_Hetero_Arch_Flag" + for key_param in ${install_info_key_array}; do + if [ "${key_param}" = "${_key}" ]; then + _param=$(grep -i "${_key}=" "${_file}" | cut -d"=" -f2-) + break + fi + done + echo "${_param}" +} + +install_info="${common_parse_dir}/metadef/ascend_install.info" +if [ -f "$install_info" ]; then + hetero_arch=$(get_install_param "METADEF_Hetero_Arch_Flag" "${install_info}") +fi + +# 写日志 +log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + local log_type="$1" + local log_msg="$2" + local log_format="[metadef] [$cur_date] [$log_type]: $log_msg" + if [ "$log_type" = "INFO" ]; then + echo "$log_format" + elif [ "$log_type" = "WARNING" ]; then + echo "$log_format" + elif [ "$log_type" = "ERROR" ]; then + echo "$log_format" + elif [ "$log_type" = "DEBUG" ]; then + echo "$log_format" 1> /dev/null + fi + echo "$log_format" >> "$logfile" +} + +########################################################################## +log "INFO" "step into run_metadef_uninstall.sh ......" +log "INFO" "uninstall target dir $common_parse_dir, type $common_parse_type." + +if [ ! -d "$common_parse_dir/metadef" ]; then + log "ERROR" "ERR_NO:0x0001;ERR_DES:path $common_parse_dir/metadef is not exist." + exit 1 +fi + +new_uninstall() { + if [ -f "${common_parse_dir}/metadef/data/version.info" ]; then + log "INFO" "need to uninstall costmodel files." + bash "${common_parse_dir}/metadef/data/script/install.sh" -- -- --uninstall --install-path="${common_parse_dir}" + fi + + if [ ! -d "${common_parse_dir}/metadef" ]; then + log "INFO" "no need to uninstall metadef files." + return 0 + fi + + # 赋可写权限 + chmod +w -R "${SOURCE_INSTALL_COMMON_PARSER_FILE}" + + if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" = "y" ]; then + local package_db_info="$common_parse_dir/var/ascend_package_db.info" + if [ -e "$package_db_info" ]; then + local linux_path="$(realpath $common_parse_dir/..)" + local arch_path="$(basename $linux_path)" + local latest_path="$(realpath $linux_path/../..)/latest" + local pkgs="$(cut -d'|' -f2 $package_db_info | sort -u)" + if [ "$pkgs" = "metadef" ]; then + if [ -L "$latest_path/$arch_path" ] && [ "$(realpath $linux_path)" = "$(realpath $latest_path/$arch_path)" ]; then + rm -f "$latest_path/$arch_path" + fi + elif [ -n "$pkgs" ] && [ -d "$latest_path" ]; then + if [ ! -e "$latest_path/$arch_path" ] || [ -L "$latest_path/$arch_path" ]; then + ln -srfn "$linux_path" "$latest_path" + fi + fi + fi + fi + + # 执行卸载 + custom_options="--custom-options=--common-parse-dir=$common_parse_dir,--logfile=$logfile,--stage=uninstall,--quiet=$is_quiet,--hetero-arch=$hetero_arch" + sh "$SOURCE_INSTALL_COMMON_PARSER_FILE" --package="metadef" --uninstall --username="$username" --usergroup="$usergroup" ${recreate_softlink_option} \ + --version=$pkg_version --version-dir=$pkg_version_dir \ + --docker-root="$docker_root" $custom_options "$common_parse_type" "$input_install_dir" "$SOURCE_FILELIST_FILE" + if [ $? -ne 0 ]; then + log "ERROR" "ERR_NO:0x0090;ERR_DES:failed to uninstall package." + return 1 + fi + + if [ -n "$latest_path" ] && [ -d "$latest_path" ] && [ "x$(ls -A $latest_path 2>&1)" = "x" ]; then + rm -rf "$latest_path" + fi + + return 0 +} + +new_uninstall +if [ $? -ne 0 ]; then + exit 1 +fi + +exit 0 diff --git a/scripts/package/metadef/scripts/run_metadef_upgrade.sh b/scripts/package/metadef/scripts/run_metadef_upgrade.sh new file mode 100644 index 0000000000000000000000000000000000000000..50095b0f333a51412847ae98221f969bef45aa5e --- /dev/null +++ b/scripts/package/metadef/scripts/run_metadef_upgrade.sh @@ -0,0 +1,172 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. + +# The code snippet comes from Huawei's open-source Ascend project. +# Copyright 2019-2020 Huawei Technologies Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# ---------------------------------------------------------------------------- + +username="$(id -un)" +usergroup="$(id -gn)" +is_quiet=n +pylocal=n +in_install_for_all=n +setenv_flag=n +docker_root="" +sourcedir="$PWD/metadef" +curpath=$(dirname $(readlink -f "$0")) +common_func_path="${curpath}/common_func.inc" +pkg_version_path="${curpath}/../../version.info" +chip_type="all" +feature_type="all" + +. "${common_func_path}" + +if [ "$1" ]; then + input_install_dir="${2}" + common_parse_type="${3}" + is_quiet="${4}" + pylocal="${5}" + setenv_flag="${6}" + docker_root="${7}" + in_install_for_all="${8}" +fi + +if [ "x${docker_root}" != "x" ]; then + common_parse_dir="${docker_root}${input_install_dir}" +else + common_parse_dir="${input_install_dir}" +fi + +get_version "pkg_version" "$pkg_version_path" +is_multi_version_pkg "pkg_is_multi_version" "$pkg_version_path" +if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" != "y" ]; then + get_version_dir "pkg_version_dir" "$pkg_version_path" + common_parse_dir="$common_parse_dir/$pkg_version_dir" +fi + +if [ $(id -u) -ne 0 ]; then + log_dir="${HOME}/var/log/ascend_seclog" +else + log_dir="/var/log/ascend_seclog" +fi +logfile="${log_dir}/ascend_install.log" + +get_install_param() { + local _key="$1" + local _file="$2" + local _param="" + + if [ ! -f "${_file}" ]; then + exit 1 + fi + local install_info_key_array="METADEF_Install_Type METADEF_Chip_Type METADEF_Feature_Type METADEF_UserName METADEF_UserGroup METADEF_Install_Path_Param METADEF_Arch_Linux_Path METADEF_Hetero_Arch_Flag" + for key_param in ${install_info_key_array}; do + if [ "${key_param}" = "${_key}" ]; then + _param=$(grep -i "${_key}=" "${_file}" | cut -d"=" -f2-) + break + fi + done + echo "${_param}" +} + +install_info="${common_parse_dir}/metadef/ascend_install.info" +if [ -f "$install_info" ]; then + chip_type=$(get_install_param "METADEF_Chip_Type" "${install_info}") + feature_type=$(get_install_param "METADEF_Feature_Type" "${install_info}") + hetero_arch=$(get_install_param "METADEF_Hetero_Arch_Flag" "${install_info}") +fi + +# 写日志 +log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + local log_type="$1" + shift + if [ "$log_type" = "INFO" -o "$log_type" = "WARNING" -o "$log_type" = "ERROR" ]; then + echo -e "[metadef] [$cur_date] [$log_type]: $*" + else + echo "[metadef] [$cur_date] [$log_type]: $*" 1> /dev/null + fi + echo "[metadef] [$cur_date] [$log_type]: $*" >> "$logfile" +} + +# 静默模式日志打印 +new_echo() { + local log_type="$1" + local log_msg="$2" + if [ "${is_quiet}" = "n" ]; then + echo "${log_type}" "${log_msg}" 1> /dev/null + fi +} + +output_progress() { + new_echo "INFO" "upgrade upgradePercentage:$1%" + log "INFO" "upgrade upgradePercentage:$1%" +} + +create_latest_linux_softlink() { + if [ "$pkg_is_multi_version" = "true" ] && [ "$hetero_arch" = "y" ]; then + local linux_path="$(realpath $common_parse_dir/..)" + local arch_path="$(basename $linux_path)" + local latest_path="$(realpath $linux_path/../..)/latest" + if [ -d "$latest_path" ]; then + if [ ! -e "$latest_path/$arch_path" ] || [ -L "$latest_path/$arch_path" ]; then + ln -srfn "$linux_path" "$latest_path" + fi + fi + fi +} + +########################################################################## +log "INFO" "step into run_metadef_upgrade.sh ......" +log "INFO" "upgrade target dir $common_parse_dir, type $common_parse_type." + +if [ ! -d "$common_parse_dir" ]; then + log "ERROR" "ERR_NO:0x0001;ERR_DES:path $common_parse_dir is not exist." + exit 1 +fi + +new_upgrade() { + if [ ! -d "${sourcedir}" ]; then + log "INFO" "no need to upgrade metadef files." + return 0 + fi + output_progress 10 + + local setenv_option="" + if [ "${setenv_flag}" = y ]; then + setenv_option="--setenv" + fi + + # 执行安装 + custom_options="--custom-options=--common-parse-dir=$common_parse_dir,--logfile=$logfile,--stage=upgrade,--quiet=$is_quiet,--pylocal=$pylocal,--hetero-arch=$hetero_arch" + sh "$curpath/install_common_parser.sh" --package="metadef" --install --username="$username" --usergroup="$usergroup" --set-cann-uninstall --upgrade \ + --version=$pkg_version --version-dir=$pkg_version_dir \ + $setenv_option $in_install_for_all --docker-root="$docker_root" --chip="$chip_type" --feature="$feature_type" \ + $custom_options "$common_parse_type" "$input_install_dir" "$curpath/filelist.csv" + if [ $? -ne 0 ]; then + log "ERROR" "ERR_NO:0x0085;ERR_DES:failed to install package." + return 1 + fi + + create_latest_linux_softlink + return 0 +} + +new_upgrade +if [ $? -ne 0 ]; then + exit 1 +fi + +output_progress 100 +exit 0 diff --git a/scripts/package/metadef/scripts/setenv.bash b/scripts/package/metadef/scripts/setenv.bash new file mode 100644 index 0000000000000000000000000000000000000000..13b2bef977a1ed8326b3ca98efdd7fadf1041a54 --- /dev/null +++ b/scripts/package/metadef/scripts/setenv.bash @@ -0,0 +1,89 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +curpath="$(dirname ${BASH_SOURCE:-$0})" +curfile="$(realpath ${BASH_SOURCE:-$0})" +param_mult_ver=$1 + +get_install_param() { + local _key="$1" + local _file="$2" + local _param="" + + if [ ! -f "${_file}" ]; then + exit 1 + fi + local install_info_key_array="METADEF_Install_Type METADEF_Feature_Type METADEF_UserName METADEF_UserGroup METADEF_Install_Path_Param METADEF_Arch_Linux_Path METADEF_Hetero_Arch_Flag" + for key_param in ${install_info_key_array}; do + if [ "${key_param}" = "${_key}" ]; then + _param=$(grep -i "${_key}=" "${_file}" | cut --only-delimited -d"=" -f2-) + break + fi + done + echo "${_param}" +} + +get_install_dir() { + local install_info="$curpath/../ascend_install.info" + local hetero_arch=$(get_install_param "METADEF_Hetero_Arch_Flag" "${install_info}") + if [ "$param_mult_ver" = "multi_version" ]; then + if [ "$hetero_arch" = "y" ]; then + echo "$(realpath $curpath/../../../../../latest)/metadef" + else + echo "$(realpath $curpath/../../../latest)/metadef" + fi + else + echo "$(realpath $curpath/..)" + fi +} + +INSTALL_DIR="$(get_install_dir)" +lib_path="${INSTALL_DIR}/python/site-packages/" +if [ -d "${lib_path}" ]; then + python_path="${PYTHONPATH}" + num=$(echo ":${python_path}:" | grep ":${lib_path}:" | wc -l) + if [ "${num}" -eq 0 ]; then + if [ "-${python_path}" = "-" ]; then + export PYTHONPATH="${lib_path}" + else + export PYTHONPATH="${lib_path}:${python_path}" + fi + fi +fi + +library_path="${INSTALL_DIR}/lib64" +if [ -d "${library_path}" ]; then + ld_library_path="${LD_LIBRARY_PATH}" + num=$(echo ":${ld_library_path}:" | grep ":${library_path}:" | wc -l) + if [ "${num}" -eq 0 ]; then + if [ "-${ld_library_path}" = "-" ]; then + export LD_LIBRARY_PATH="${library_path}:${library_path}/plugin/opskernel:${library_path}/plugin/nnengine:${library_path}/stub" + else + export LD_LIBRARY_PATH="${library_path}:${library_path}/plugin/opskernel:${library_path}/plugin/nnengine:${ld_library_path}:${library_path}/stub" + fi + fi +fi + +custom_path_file="$INSTALL_DIR/../conf/path.cfg" +common_interface="$INSTALL_DIR/script/common_interface.bash" +owner=$(stat -c %U "$curfile") +if [ $(id -u) -ne 0 ] && [ "$owner" != "$(whoami)" ] && [ -f "$custom_path_file" ] && [ -f "$common_interface" ]; then + . "$common_interface" + mk_custom_path "$custom_path_file" + for dir_name in "conf" "data"; do + dst_dir="$(grep -w "$dir_name" "$custom_path_file" | cut --only-delimited -d"=" -f2-)" + eval "dst_dir=$dst_dir" + if [ -d "$INSTALL_DIR/$dir_name" ] && [ -d "$dst_dir" ]; then + chmod -R u+w $dst_dir/* > /dev/null 2>&1 + cp -rfL $INSTALL_DIR/$dir_name/* "$dst_dir" + fi + done +fi diff --git a/scripts/package/metadef/scripts/setenv.csh b/scripts/package/metadef/scripts/setenv.csh new file mode 100644 index 0000000000000000000000000000000000000000..2c7fbc5b953b588b44088bd74d5742a36a274fde --- /dev/null +++ b/scripts/package/metadef/scripts/setenv.csh @@ -0,0 +1,72 @@ +#!/usr/bin/env csh +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +set CURFILE=`readlink -f ${1}` +set CURPATH=`dirname ${CURFILE}` + +set install_info="$CURPATH/../ascend_install.info" +set hetero_arch=`grep -i "METADEF_Hetero_Arch_Flag=" "$install_info" | cut --only-delimited -d"=" -f2` +if ( "$2" == "multi_version" ) then + if ( "$hetero_arch" == "y" ) then + set INSTALL_DIR="`realpath ${CURPATH}/../../../../../latest`/metadef" + else + set INSTALL_DIR="`realpath ${CURPATH}/../../../latest`/metadef" + endif +else + set INSTALL_DIR="`realpath ${CURPATH}/..`" +endif + +set lib_path="${INSTALL_DIR}/python/site-packages/" +if ( -d "${lib_path}" ) then + set python_path="" + if ( $?PYTHONPATH == 1 ) then + set python_path="$PYTHONPATH" + endif + set num=`echo ":${python_path}:" | grep ":${lib_path}:" | wc -l` + if ( "${num}" == 0 ) then + if ( "-${python_path}" == "-" ) then + setenv PYTHONPATH ${lib_path} + else + setenv PYTHONPATH ${lib_path}:${python_path} + endif + endif +endif + +set library_path="${INSTALL_DIR}/lib64" +if ( -d "${library_path}" ) then + set ld_library_path="" + if ( $?LD_LIBRARY_PATH == 1 ) then + set ld_library_path="$LD_LIBRARY_PATH" + endif + set num=`echo ":${ld_library_path}:" | grep ":${library_path}:" | wc -l` + if ( "$num" == 0 ) then + if ( "-${ld_library_path}" == "-" ) then + setenv LD_LIBRARY_PATH "${library_path}:${library_path}/plugin/opskernel:${library_path}/plugin/nnengine:${library_path}/stub" + else + setenv LD_LIBRARY_PATH "${library_path}:${library_path}/plugin/opskernel:${library_path}/plugin/nnengine:${ld_library_path}:${library_path}/stub" + endif + endif +endif + +set custom_path_file="$INSTALL_DIR/../conf/path.cfg" +set common_interface="$INSTALL_DIR/script/common_interface.csh" +set owner="`stat -c %U $CURFILE`" +if ( "`id -u`" != 0 && "`id -un`" != "$owner" && -f "$custom_path_file" && -f "$common_interface" ) then + csh -f "$common_interface" mk_custom_path "$custom_path_file" + foreach dir_name ("conf" "data") + set dst_dir="`grep -w "$dir_name" "$custom_path_file" | cut --only-delimited -d"=" -f2-`" + set dst_dir="`eval echo $dst_dir`" + if ( -d "$INSTALL_DIR/$dir_name" && -d "$dst_dir" ) then + chmod -R u+w $dst_dir/* >& /dev/null + cp -rfL $INSTALL_DIR/$dir_name/* "$dst_dir" + endif + end +endif diff --git a/scripts/package/metadef/scripts/setenv.fish b/scripts/package/metadef/scripts/setenv.fish new file mode 100644 index 0000000000000000000000000000000000000000..d968340bce30fce795818b97cd9ad481da9064a5 --- /dev/null +++ b/scripts/package/metadef/scripts/setenv.fish @@ -0,0 +1,86 @@ +#!/usr/bin/env fish +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +set -g curpath (realpath (dirname (status --current-filename))) +set -g curfile (realpath (status --current-filename)) +set -g param_mult_ver $argv[1] + +function get_install_param + set -l _key $argv[1] + set -l _file $argv[2] + if not test -f "$_file" + exit 1 + end + set -l install_info_key_array METADEF_Install_Type METADEF_Feature_Type METADEF_UserName METADEF_UserGroup METADEF_Install_Path_Param METADEF_Arch_Linux_Path METADEF_Hetero_Arch_Flag + for key_param in $install_info_key_array + if test "$key_param" = "$_key" + grep -i "$_key=" "$_file" | cut --only-delimited -d"=" -f2- + break + end + end +end + +function get_install_dir + set -l install_info "$curpath/../ascend_install.info" + set -l hetero_arch (get_install_param "METADEF_Hetero_Arch_Flag" "$install_info") + if test "$param_mult_ver" = "multi_version" + if test "$hetero_arch" = "y" + echo (realpath $curpath/../../../../../latest)/metadef + else + echo (realpath $curpath/../../../latest)/metadef + end + else + echo (realpath $curpath/..) + end +end + +set -l INSTALL_DIR (get_install_dir) +set -l lib_path "$INSTALL_DIR/python/site-packages/" +if test -d "$lib_path" + set -l python_path "$PYTHONPATH" + set -l num (echo ":$python_path:" | grep ":$lib_path:" | wc -l) + if test "$num" -eq 0 + if test "-$python_path" = "-" + set -gx PYTHONPATH "$lib_path" + else + set -gx PYTHONPATH "$lib_path:$python_path" + end + end +end + +set -l library_path "$INSTALL_DIR/lib64" +if test -d "$library_path" + set -l ld_library_path "$LD_LIBRARY_PATH" + set -l num (echo ":$ld_library_path:" | grep ":$library_path:" | wc -l) + if test "$num" -eq 0 + if test "-$ld_library_path" = "-" + set -gx LD_LIBRARY_PATH "$library_path:$library_path/plugin/opskernel:$library_path/plugin/nnengine:$library_path/stub" + else + set -gx LD_LIBRARY_PATH "$library_path:$library_path/plugin/opskernel:$library_path/plugin/nnengine:$ld_library_path:$library_path/stub" + end + end +end + +set -l custom_path_file "$INSTALL_DIR/../conf/path.cfg" +set -l common_interface "$INSTALL_DIR/script/common_interface.fish" +set -l owner (stat -c \%U "$curfile") +if test (id -u) -ne 0 -a (id -un) != "$owner" -a -f "$custom_path_file" -a -f "$common_interface" + . "$common_interface" + mk_custom_path "$custom_path_file" + for dir_name in "conf" "data" + set -l dst_dir (grep -w "$dir_name" "$custom_path_file" | cut --only-delimited -d"=" -f2-) + set -l dst_dir (eval echo "$dst_dir") + if test -d "$INSTALL_DIR/$dir_name" -a -d "$dst_dir" + chmod -R u+w $dst_dir/* > /dev/null 2>&1 + cp -rfL $INSTALL_DIR/$dir_name/* "$dst_dir" + end + end +end diff --git a/scripts/package/metadef/scripts/uninstall.sh b/scripts/package/metadef/scripts/uninstall.sh new file mode 100644 index 0000000000000000000000000000000000000000..a8ae31eb11a33f74b7de496c1a45644e7858c006 --- /dev/null +++ b/scripts/package/metadef/scripts/uninstall.sh @@ -0,0 +1,326 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +############### 全局变量定义 ############### +HOST="127.0.0.1" +RUN_USERNAME="$(id -un)" # 当前执行用户 +DEFAULT_ROOT_DIR="/usr/local/Ascend" # 根用户默认安装路径 +DEFAULT_NORMAL_DIR="${HOME}/Ascend" # 普通用户默认安装路径 + +curpath="$(dirname $(readlink -f $0))" # 脚本目录 +common_func_path="${curpath}/common_func.inc" +metadef_func_path="${curpath}/metadef_func.sh" +UNINSTALL_SHELL="${curpath}/run_metadef_uninstall.sh" # 卸载脚本路径 +install_path_param="$(dirname "${curpath}")" + +SCENE_INFO_FILE="$install_path_param/scene.info" +version_info_file="$install_path_param/version.info" +ASCEND_INSTALL_INFO_FILE="$install_path_param/ascend_install.info" +ASCEND_INSTALL_INFO_OLD_FILE="/etc/ascend_install.info" + +RUN_CMD="uninstall" # 执行程序命令 +RUN_CMD_TYPE="Uninstall" # 执行程序命令类型 +IS_QUIET="n" # 静默模式默认为否 + +. "${common_func_path}" +. "${metadef_func_path}" + +# 执行程序等级 +case "${RUN_CMD_TYPE}" in + Install) + LEVEL="SUGGESTION" + ;; + Upgrade) + LEVEL="MINOR" + ;; + Uninstall) + LEVEL="MAJOR" + ;; + *) + LEVEL="UNKNOWN" + ;; +esac + +if [ "$1" ]; then + RUN_FILE_NAME="$(expr substr $1 5 $(expr ${#1} - 4))" +fi + +# 判断当前用户身份, 指定日志和安装路径 +if [ $(id -u) -ne 0 ]; then + LOG_DIR="${HOME}/var/log/ascend_seclog" # 普通用户日志存放目录 + DEFAULT_INSTALL_PATH="${HOME}/Ascend" # 普通用户默认安装路径 +else + LOG_DIR="/var/log/ascend_seclog" # 根用户日志存放目录 + DEFAULT_INSTALL_PATH="/usr/local/Ascend" # 根用户默认安装路径 +fi + +logfile="${LOG_DIR}/ascend_install.log" # 安装日志文件路径 +OPERATION_LOG_FILE="${LOG_DIR}/operation.log" # 操作日志路径 + +############### 日志函数 ############### +# 过程日志打印 +log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + local log_type="$1" + local log_msg="$2" + local log_format="[metadef] [$cur_date] [$log_type]: $log_msg" + if [ "$log_type" = "INFO" ]; then + echo "$log_format" + elif [ "$log_type" = "WARNING" ]; then + echo "$log_format" + elif [ "$log_type" = "ERROR" ]; then + echo "$log_format" + elif [ "$log_type" = "DEBUG" ]; then + echo "$log_format" 1> /dev/null + fi + echo "$log_format" >> "$logfile" +} + +# 静默模式日志打印 +new_echo() { + local log_type="$1" + local log_msg="$2" + if [ "${is_quiet}" = "n" ]; then + echo "${log_type}" "${log_msg}" 1> /dev/null + fi +} + +# 开始执行前打印开始信息 +start_log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + new_echo "INFO" "Start time:${cur_date}" + log "INFO" "Start time:${cur_date}" + log "INFO" "LogFile:${logfile}" + log "INFO" "InputParams:--${RUN_CMD}" +} + +# 退出时打印结束日志 +exit_log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + new_echo "INFO" "End time:${cur_date}" + log "INFO" "End time:${cur_date}" + exit "$1" +} + +# 打印操作日志 +log_operation() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + if [ ! -f "${OPERATION_LOG_FILE}" ]; then + touch "${OPERATION_LOG_FILE}" + chmod 640 "${OPERATION_LOG_FILE}" + fi + echo "${RUN_CMD_TYPE} ${LEVEL} ${RUN_USERNAME} ${cur_date} ${HOST} metadef $2 installmode=${RUN_CMD}; cmdlist=--${RUN_CMD}" >> "${OPERATION_LOG_FILE}" +} + +############### 错误函数 ############### +# 不支持的参数 +err_no0x0004() { + log "ERROR" "ERR_NO:0x0004;ERR_DES: Unrecognized parameters: $1" + exit_log 1 +} + +# 文件没有找到 +err_no0x0080() { + log "ERROR" "ERR_NO:0x0080;ERR_DES:This file or directory does not exist, $1" + exit_log 1 +} + +# 用户权限不足 +err_no0x0093() { + log "ERROR" "ERR_NO:0x0093;ERR_DES:Permission denied, $1" + exit_log 1 +} + +############### 环境适配函数 ############### +chmod_start() { + chmod -R 750 "$install_path_param" +} + +############### 检验函数 ############### +# 用户权限认证 +user_auth() { + local dir_user_id=$(stat -c "%u" "$install_path_param") + local run_user_id=$(id -u) + if [ "${run_user_id}" -ne 0 ]; then + if [ "${run_user_id}" -ne "${dir_user_id}" ]; then + err_no0x0093 "Current user is not supported to ${RUN_CMD} the metadef package" + fi + fi +} + +get_install_param() { + local _key="$1" + local _file="$2" + local _param="" + + if [ ! -f "${_file}" ]; then + exit 1 + fi + local install_info_key_array="METADEF_Install_Type METADEF_Feature_Type METADEF_UserName METADEF_UserGroup METADEF_Install_Path_Param METADEF_Arch_Linux_Path METADEF_Hetero_Arch_Flag" + for key_param in ${install_info_key_array}; do + if [ "${key_param}" = "${_key}" ]; then + _param=$(grep -i "${_key}=" "${_file}" | cut -d"=" -f2-) + break + fi + done + echo "${_param}" +} + +hetero_arch=$(get_install_param "METADEF_Hetero_Arch_Flag" "${ASCEND_INSTALL_INFO_FILE}") +export hetero_arch +get_version_dir "version_dir" "$version_info_file" + +get_pkg_install_path_param() { + if [ -n "$version_dir" ] && [ "$hetero_arch" != "y" ]; then + realpath "$install_path_param/../.." + else + realpath "$install_path_param/.." + fi +} + +get_install_top_path() { + local pkg_install_path_param="$(get_pkg_install_path_param)" + if [ "$hetero_arch" = "y" ]; then + if [ -n "$version_dir" ]; then + realpath "$pkg_install_path_param/../../../.." + else + realpath "$pkg_install_path_param/../../.." + fi + else + realpath "$pkg_install_path_param/.." + fi +} + +save_user_files_to_log() { + if [ "$1" = "$install_path_param" ] && [ -s "$1" ]; then + local filenum=$(ls -lR "$1"|grep "^-"|wc -l) + local dirnum=$(ls -lR "$1"|grep "^d"|wc -l) + local totalnum=$(expr "${filenum}" + "${dirnum}") + if [ "$totalnum" -eq 2 ]; then + if [ -f "${version_info_file}" ] && [ -f "${ASCEND_INSTALL_INFO_FILE}" ]; then + return 0 + fi + fi + if [ "$totalnum" -eq 1 ]; then + if [ -f "${version_info_file}" ] || [ -f "${ASCEND_INSTALL_INFO_FILE}" ]; then + return 0 + fi + fi + log "INFO" "Some files generated by user are not cleared, if necessary, manually clear them, get details in $logfile" + fi + if [ -s "$1" ]; then + for file in $(ls -a "$1"); do + if [ -d "$1/$file" -a ! -L "$1/$file" ]; then + if [ "$file" != '.' ] && [ "$file" != '..' ]; then + echo "$1/$file" >> "$logfile" + save_user_files_to_log "$1/$file" + fi + else + echo "$1/$file" >> "$logfile" + fi + done + fi +} + +############### 执行函数 ############### +uninstall_run() { + user_auth + chmod_start + local num=0 + local operation="${RUN_CMD_TYPE}" + local metadef_install_path_param="$(get_pkg_install_path_param)" + local install_top_path="$(get_install_top_path)" + + if [ -f "$ASCEND_INSTALL_INFO_FILE" ]; then + local metadef_install_type=$(get_install_param "METADEF_Install_Type" "${ASCEND_INSTALL_INFO_FILE}") + elif [ -f "${ASCEND_INSTALL_INFO_OLD_FILE}" ]; then + num=$(grep -c -i metadef_install_path_param "${ASCEND_INSTALL_INFO_OLD_FILE}") + if [ "${num}" != "0" ]; then + local metadef_install_type="$(grep -iw metadef_install_type "$ASCEND_INSTALL_INFO_OLD_FILE" | cut -d"=" -f2-)" + fi + else + err_no0x0080 "please complete ${ASCEND_INSTALL_INFO_FILE} or ${ASCEND_INSTALL_INFO_OLD_FILE}" + fi + if [ $? -eq 0 ]; then + log "INFO" "${RUN_CMD} ${metadef_install_path_param} ${metadef_install_type}" + bash "${UNINSTALL_SHELL}" "${RUN_CMD}" "${metadef_install_path_param}" "${metadef_install_type}" "${IS_QUIET}" "n" "" "y" + if [ $? -eq 0 ]; then + rm -f "${ASCEND_INSTALL_INFO_FILE}" + rm -f "${version_info_file}" + if [ $? -eq 0 ] && [ -f "${ASCEND_INSTALL_INFO_OLD_FILE}" ] && [ -w "${ASCEND_INSTALL_INFO_OLD_FILE}" ] && [ "${num}" != "0" ]; then + sed -i '/metadef_install_path_param=/Id' "${ASCEND_INSTALL_INFO_OLD_FILE}" + sed -i '/metadef_install_type=/Id' "${ASCEND_INSTALL_INFO_OLD_FILE}" + fi + remove_dir_recursive "$install_top_path" "$install_path_param" + new_echo "INFO" "metadef package uninstalled successfully! Uninstallation takes effect immediately." + log "INFO" "metadef package uninstalled successfully! Uninstallation takes effect immediately." + log_operation "${operation}" "succeeded" + save_user_files_to_log "$install_path_param" + save_user_files_to_log "$(dirname $install_path_param)/atc" + save_user_files_to_log "$(dirname $install_path_param)/fwkacllib" + else + log "WARNING" "${operation}" "failed" + log_operation "${operation}" "failed" + exit_log 1 + fi + fi + return $? +} + +############### 程序执行 ############### +while true +do + case "$1" in + --quiet) + IS_QUIET="y" + shift + ;; + --hetero-arch) + in_hetero_arch="y" + shift + ;; + *) + if [ "x$1" != "x" ]; then + err_no0x0004 "$1 . Only support '--quiet' and '--hetero-arch'." + fi + break + ;; + esac +done + +if [ "$hetero_arch" != "y" ]; then + arch_path="$(dirname "$install_path_param")/$arch_scripts_path_hetero/metadef/script/uninstall.sh" + ret=0 + if [ -f "$arch_path" ]; then + bash "$arch_path" + ret=$? + elif [ "$in_hetero_arch" = "y" ]; then + log "WARNING" "no hetero arch metadef package installed!" + fi + if [ "$in_hetero_arch" = "y" ]; then + exit $ret + fi +fi + +# 输出执行开始日志 +start_log + +# 验证此目录是否为空 +is_dir_empty "$install_path_param" +if [ $? -ne 0 ]; then + # 执行卸载 + uninstall_run +else + # 报错 + err_no0x0080 "runfile is not installed on this device, uninstall failed" +fi + +exit_log 0 diff --git a/scripts/package/metadef/scripts/ver_check.sh b/scripts/package/metadef/scripts/ver_check.sh new file mode 100644 index 0000000000000000000000000000000000000000..594cb6703f1af6ceae208dc374169f72e2468828 --- /dev/null +++ b/scripts/package/metadef/scripts/ver_check.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify it. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +############### 全局变量定义 ############### +CURPATH=$(dirname $(readlink -f "$0")) # 当前路径 +COMMON_FUNC="${CURPATH}/common_func.inc" # 公共 +DEP_INFO_FILE="/etc/ascend_install.info" + +if [ ! "$1" ]; then + version_info_file="$(dirname ${CURPATH})/version.info" + DEP_PKG_NAME="driver" + driver_install_path_param="$(grep -iw driver_install_path_param $DEP_INFO_FILE | cut -d"=" -f2-)" + DEP_PKG_VER_FILE="${driver_install_path_param}/${DEP_PKG_NAME}/version.info" +else + version_info_file="$1" + DEP_PKG_NAME="$2" # 依赖包名 + DEP_PKG_VER_FILE="$3" # 依赖包路径 +fi + +# 写日志 +log() { + local cur_date="$(date +'%Y-%m-%d %H:%M:%S')" + echo "[Compiler] [$cur_date] $*" +} + +main() { + if [ ! -f "$version_info_file" ]; then + log "[WARNING]: file $version_info_file not exists!" + return 0 + fi + + if [ ! -f "$DEP_PKG_VER_FILE" ]; then + log "[WARNING]: file $DEP_PKG_VER_FILE not exists!" + return 0 + fi + + . "${COMMON_FUNC}" + check_pkg_ver_deps "${version_info_file}" "${DEP_PKG_NAME}" "${DEP_PKG_VER_FILE}" + + if [ "${ver_check_status}" = "SUCC" ]; then + log "[INFO]: Check version matched!" + return 0 + else + log "[WARNING]: Check version does not matched!" + return 1 + fi +} + +main diff --git a/scripts/package/module/ascend/EngineeringCommon.xml b/scripts/package/module/ascend/EngineeringCommon.xml new file mode 100644 index 0000000000000000000000000000000000000000..6f974ee2dee296055497064129b0f7ca3981cfbc --- /dev/null +++ b/scripts/package/module/ascend/EngineeringCommon.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/scripts/package/module/ascend/EngineeringFiles.xml b/scripts/package/module/ascend/EngineeringFiles.xml new file mode 100644 index 0000000000000000000000000000000000000000..fc3174406a7e5b231aef541c27b1de2f8777bf59 --- /dev/null +++ b/scripts/package/module/ascend/EngineeringFiles.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/scripts/package/module/ascend/MetadefInc.xml b/scripts/package/module/ascend/MetadefInc.xml new file mode 100644 index 0000000000000000000000000000000000000000..9557476e6368b2871ea62a5b6f54f228f264a5c8 --- /dev/null +++ b/scripts/package/module/ascend/MetadefInc.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scripts/package/module/ascend/MetadefSo.xml b/scripts/package/module/ascend/MetadefSo.xml new file mode 100644 index 0000000000000000000000000000000000000000..435dcac0875642688681cfd5f90f294827089bd2 --- /dev/null +++ b/scripts/package/module/ascend/MetadefSo.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scripts/package/package.py b/scripts/package/package.py new file mode 100644 index 0000000000000000000000000000000000000000..e01ed80975e9fd014b78643612b3c6f707ec4389 --- /dev/null +++ b/scripts/package/package.py @@ -0,0 +1,694 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +# ---------------------------------------------------------------------------- +# This program is free software, you can redistribute it and/or modify. +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# This file is a part of the CANN Open Software. +# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of +# the software repository for the full text of the License. +# ---------------------------------------------------------------------------- + +import os +import sys +import argparse +import traceback +import csv +from argparse import Namespace +from collections import namedtuple +from datetime import datetime, timezone +from functools import partial +from itertools import chain +from typing import Dict, Iterator, List, Set, Tuple, TextIO + +from common.py.utils import pkg_utils +from common.py.filelist import ( + FileItem, FileList, check_filelist, create_file_item, generate_filelist, + get_transform_nested_path_func, +) +from common.py.packer import ( + PackageName, create_makeself_pkg_params_factory, create_run_package_command +) +from common.py.pkg_parser import ( + ParseOption, XmlConfig, parse_xml_config, get_cann_version_info +) +from common.py.utils.pkg_utils import ( + CONFIG_SCRIPT_PATH, CompressError, ContainAsteriskError, DELIVERY_PATH, FAIL, + FilelistError, GenerateFilelistError, PackageNameEmptyError, SUCCESS, TOP_DIR, + UnknownOperateTypeError, path_join +) +from common.py.utils.funcbase import invoke, pipe +from common.py.utils.comm_log import CommLog + + +def get_comments(package_name: PackageName) -> str: + """获取run包注释。""" + comments = '_'.join( + [package_name.product_name.upper(), package_name.func_name.upper(), 'RUN_PACKAGE'] + ) + return f'"{comments}"' + + +def get_compress_cmd(pkg_args: Namespace, + xml_config: XmlConfig) -> str: + """获取makeself压缩命令""" + suffix = xml_config.package_attr.get('suffix') + if suffix == "run": + package_name = PackageName(xml_config.package_attr, pkg_args, xml_config.version) + factory = create_makeself_pkg_params_factory( + package_name.getvalue(), get_comments(package_name) + ) + params = factory(xml_config.package_attr) + pack_cmd, err_msg = create_run_package_command(params) + if err_msg: + CommLog.cilog_error(err_msg) + CommLog.cilog_error("create_run_command failed!") + else: + CommLog.cilog_error("the repack type '%s' is not support!", suffix) + sys.exit(FAIL) + try: + makeself_dir = os.path.join(TOP_DIR, "build/makeself.txt") + with open(makeself_dir, 'w') as f: + f.write(pack_cmd) + except Exception as exception: + CommLog.cilog_error(f"save makeself.txt failed!{str(exception)}") + sys.exit(FAIL) + return package_name.getvalue() + + +def make_parse_option(args_: argparse.Namespace) -> ParseOption: + """创建解析参数。""" + + return ParseOption( + args_.os_arch, args_.pkg_version, + args_.build_type, + args_.package_check, + args_.ext_name + ) + + +PrivatePackageOption = namedtuple( + 'PrivatePackageOption', + [ + 'os_arch', 'package_suffix', 'not_in_name', 'pkg_version', 'ext_name', + 'chip_name', 'func_name', 'version_dir', 'disable_multi_version', 'suffix' + ] +) + + +class PackageOption(PrivatePackageOption): + """打包配置参数。""" + __slots__ = () # 优化内存,避免创建 __dict__ + + def __new__(cls, *package_option_args, **kwargs): + return super().__new__(cls, *package_option_args, **kwargs) + + +def generate_info_content(target_conf, ext_name) -> List[str]: + """生成info内容。""" + + def toolchain_llvm_config() -> Iterator[Tuple[str, str]]: + if 'llvm' in ext_name: + yield 'toolchain', 'llvm' + + content_list = [ + f'{key}={value}' + for key, value in chain( + target_conf['content'].items(), toolchain_llvm_config() + ) + ] + return content_list + + +def generate_version_header_content(target_conf) -> Iterator[str]: + """生成version_header内容。""" + guard_name = target_conf['value'].replace('.', '_').upper() + yield f'#ifndef {guard_name}' + yield f'#define {guard_name}' + yield '' + for name, value in target_conf['content'].items(): + if name.endswith('_VERSION'): + version_infos = get_cann_version_info(name, value) + for version_name, version_value in version_infos: + yield f'#define {version_name} {version_value}' + else: + yield f'#define {name} {value}' + yield '' + yield f'#endif /* {guard_name} */' + yield '' + + +def generate_customized_file(target_conf, ext_name): + filepath = os.path.join(TOP_DIR, "build", target_conf.get('value')) + + generator = target_conf.get('generator', 'info') + if generator == 'version_header': + content_list = generate_version_header_content(target_conf) + else: + content_list = generate_info_content(target_conf, ext_name) + + file_content = '\n'.join(content_list) + try: + with open(filepath, 'w') as file: + file.write(file_content) + except Exception as ex: + CommLog.cilog_error(f"generate customized file {filepath} failed: {ex}!") + return FAIL + + return SUCCESS + + +def get_module(target_config) -> str: + """获取配置模块。""" + module = target_config.get('module', 'NA') + return module if module else 'NA' + + +def get_operation(operation, target_config) -> str: + """获取操作类型。""" + if operation in ('copy', 'move') and target_config.get('entity') == 'true': + return 'copy_entity' + return operation + + +def get_permission(target_config) -> str: + """获取配置权限。""" + return target_config.get('install_mod', 'NA') + + +def get_owner_group(target_config) -> str: + """获取配置属主。""" + # install_own的可能值为$username:$usergroup + # 防止变量在install_common_parser.sh中,被eval展开,添加\转义$ + # 由于awk会消耗1个\,所以需要2个转义符 + return target_config.get('install_own', 'NA').replace('$', '\\\\$') + + +def get_install_type(target_config) -> str: + """获取安装类型。""" + return target_config.get('install_type', 'NA') + + +def get_softlink(target_config) -> List[str]: + """获取配置软链。""" + softlink_str = target_config.get('install_softlink') + if not softlink_str: + return [] + return softlink_str.split(';') + + +def get_feature(target_config) -> Set[str]: + """获取配置特性。""" + return target_config['feature'] + + +def get_chip(target_config) -> Set[str]: + """获取配置芯片。""" + return target_config['chip'] + + +def get_configurable(target_config) -> str: + """获取配置是否为配置文件。""" + return target_config.get('configurable', 'FALSE') + + +def get_hash_value(target_config) -> str: + """获取配置哈希值。""" + return target_config.get('hash', 'NA') + + +def get_block(target_config) -> str: + """获取配置块信息。""" + return target_config.get('name', 'NA') + + +def get_pkg_inner_softlink(target_config) -> List[str]: + """获取配置包内软链。""" + softlink_str = target_config.get('pkg_inner_softlink') + if not softlink_str: + return [] + return softlink_str.split(';') + + +def parse_install_info(infos: List, + operate_type, + filter_key) -> Iterator[FileItem]: + """根据配置解析生成安装信息。""" + for target_config in infos: + target_name = get_target_name(target_config) + if target_config.get("optional") == 'true': + path = os.path.join(TOP_DIR, DELIVERY_PATH, target_config.get('dst_path')) + vaule = os.path.join(TOP_DIR, DELIVERY_PATH, target_config.get('dst_path'), target_name) + if not os.path.exists(path): + continue + if not os.path.exists(vaule): + continue + if operate_type in ('copy', 'move'): + relative_path_in_pkg = os.path.join(target_config.get('dst_path'), target_name) + relative_install_path = path_join(target_config.get('install_path'), target_name) + is_dir = target_config.get('is_dir', False) + elif operate_type == 'mkdir': + relative_path_in_pkg = 'NA' + relative_install_path = target_config.get('value') + is_dir = False + elif operate_type == 'del': + relative_path_in_pkg = 'NA' + relative_install_path = path_join(target_config.get('install_path'), target_name) + is_dir = False + else: + raise UnknownOperateTypeError(f"unknown operate type {operate_type}") + + if relative_install_path is None: + continue + + install_type = get_install_type(target_config) + if any(key in install_type for key in filter_key): + is_in_docker = 'TRUE' + else: + is_in_docker = 'FALSE' + + file_item = create_file_item( + get_module(target_config), + get_operation(operate_type, target_config), + relative_path_in_pkg, + relative_install_path, + is_in_docker, + get_permission(target_config), + get_owner_group(target_config), + install_type, + get_softlink(target_config), + get_feature(target_config), + 'N', + get_configurable(target_config), + get_hash_value(target_config), + get_block(target_config), + get_pkg_inner_softlink(target_config), + get_chip(target_config), + is_dir, + ) + + yield file_item + + +def execute_repack_process(xml_config: XmlConfig, + delivery_dir: str, + pkg_args: Namespace, + package_name: PackageName = None, + package_option: PackageOption = None): + """ + 功能描述: 执行打包流程(拷贝--->签名--->打包) + 返回值: SUCCESS/FAIL + """ + release_dir = os.path.join( + delivery_dir, xml_config.default_config.get('name', 'default')) + # 生成自定义文件 + for item in xml_config.generate_infos: + if generate_customized_file(item, package_option.ext_name): + return FAIL + + # 校验包中文件或目录大小 + if pkg_args.check_size == "True": + limit_list, tag = processing_csv_file( + release_dir, package_name.func_name, package_name.chip_name, pkg_args.build_type + ) + if not tag: + return FAIL + if limit_list: + abspath = os.path.abspath(release_dir) + replace_path = abspath + "/" + result = check_add_dir(replace_path, abspath, limit_list) + if not result: + return FAIL + try: + package_name = get_compress_cmd(pkg_args, xml_config) + except CompressError: + return FAIL + + CommLog.cilog_info("package %s generate filelist.csv and makeself cmd successfully!", + package_name) + return SUCCESS + + +def check_path_is_conflict(xml_config): + """ + 功能描述: 检查打包时安装路径与软连接路径是否冲突 + 参数: xml_config + 返回值: SUCCESS/FAIL + """ + install_path_list = set() + pkg_softlink_list = set() + for item in xml_config.package_content_list: + value_list = item.get('value').split('/') + target_name = value_list[-1] if value_list[-1] else value_list[-2] + if item.get('install_path'): + install_path_list.add( + os.path.join(item['install_path'], target_name) + ) + if item.get('pkg_inner_softlink'): + pkg_softlink = item.get('pkg_inner_softlink') + pkg_softlink_list.add(pkg_softlink) + if install_path_list & pkg_softlink_list: + CommLog.cilog_info('intersection:{}'.format(install_path_list & pkg_softlink_list)) + CommLog.cilog_info('path conflicting: pkg_inner_softlink dir equals install_path!!') + return FAIL + return SUCCESS + + +def checksum_value(limit_value, release_dir): + """ + 功能描叙: 校验传入的文件或目录大小是否合格 + 参数: + limit_value: limit.csv中的一行数据如[compiler/bin, 3976, 110%] + 返回值: True/False + """ + path = os.path.join(release_dir, limit_value[1]) + if len(limit_value) >= 7: + try: + max_value = int(limit_value[4]) + except ValueError: + CommLog.cilog_error("{0} configuration is not standard., Please check limit.csv.".format(path)) + return True + else: + CommLog.cilog_error("{0} configuration is less than four, Please check limit.csv.".format(path)) + return True + if not os.path.exists(path): + CommLog.cilog_warning("{0} doesn't exist, Please check limit.csv.".format(path)) + return True + size = 0 + for root, dirs, files in os.walk(path): + size += os.path.getsize(root) + for f in files: + filepath = os.path.join(root, f) + if os.path.islink(filepath): + continue + if not os.path.exists(filepath): + continue + size += os.path.getsize(os.path.join(root, f)) + if size == 0: + size = os.path.getsize(path) + if size > max_value * 1024: + CommLog.cilog_error(f"\n{path} size {size} bytes exceeds maximum {max_value * 1024} bytes") + return False + return True + + +def processing_csv_file(release_dir, package_name, chip_name, build_type): + """ + 功能描叙: 处理limit.csv文件数据 + 返回值: [],True/[],False + """ + ret = True + limit_list = [] + product = os.path.basename(os.path.dirname(release_dir)) + limit_path = os.path.join(pkg_utils.TOP_SOURCE_DIR, CONFIG_SCRIPT_PATH, "common/limit.csv") + if not os.path.exists(limit_path): + CommLog.cilog_warning("{0} doesn't exist.".format(limit_path)) + return limit_list, ret + with open(limit_path, "r") as file: + reader = csv.reader(file) + next(reader) + for data in reader: + if not data: + CommLog.cilog_warning("The limit.csv file contains empty lines.") + continue + if is_match_line(package_name, chip_name, product, build_type, data): + if data[1][-1] == "/": + limit_list.append(data[1][:-1]) + else: + limit_list.append(data[1]) + res = checksum_value(data, release_dir) + if not res: + ret = False + return limit_list, ret + + +def is_match_line(package_name, chip_name, product, build_type, data): + return package_name == data[0] and chip_name == data[5] and product == data[6] and build_type == data[7].lower() + + +def check_add_dir(package_path, dirs, limit_list, ret=True): + """ + 功能描述: 校验新增目录 + 参数: path, limit_list + 返回值: False/True + """ + for limit_path in limit_list: + if dirs == os.path.join(os.path.split(dirs)[0], limit_path): + return ret + for dir_file in os.listdir(dirs): + path = os.path.join(dirs, dir_file) + relative_path = path.replace(package_path, "") + if os.path.isfile(path) and relative_path not in limit_list: + CommLog.cilog_error("{0} is not in limit.csv file and is newly added.".format(path)) + ret = False + elif os.path.isdir(path) and relative_path not in limit_list: + ret = check_add_dir(package_path, path, limit_list, ret) + return ret + + +def get_target_name(target_conf) -> str: + """获取目标名。""" + rename = target_conf.get('rename') + if rename: + return rename + + value_list = target_conf.get('value').split('/') + target_name = value_list[-1] if value_list[-1] else value_list[-2] + return target_name + + +def gen_file_install_list(xml_config: XmlConfig, + filter_key) -> Tuple[FileList, FileList]: + """生成filelist列表。""" + file_install_list = [] + + dir_filelist = parse_install_info( + xml_config.dir_install_list, 'mkdir', filter_key + ) + move_filelist = parse_install_info( + xml_config.move_content_list, 'move', filter_key + ) + pkg_filelist = parse_install_info( + xml_config.package_content_list, 'copy', filter_key + ) + gen_filelist = parse_install_info( + xml_config.generate_infos, 'copy', filter_key + ) + # file_info中配置为文件夹,这里是被展开的文件,则需要单独删除 + del_filelist = parse_install_info( + xml_config.expand_content_list, 'del', filter_key + ) + collect_filelist = list(chain(dir_filelist, move_filelist, pkg_filelist, gen_filelist)) + collect_filelist = list(xml_config.packer_config.fill_is_common_path(collect_filelist)) + all_filelist = list(chain(collect_filelist, del_filelist)) + for file_item in all_filelist: + file_install_list.append(file_item) + + return file_install_list, [] + + +def generate_filelist_file_by_xml_config(xml_config: XmlConfig, + filter_key: List[str], + package_check: bool): + """生成文件列表文件。""" + check_move = xml_config.package_attr.get('use_move', False) + transform_nested_path_func = get_transform_nested_path_func( + xml_config.package_attr.get('parallel') or check_move + ) + check_features = xml_config.package_attr.get('check_features', False) + + file_install_list, [] = invoke( + pipe( + gen_file_install_list, + partial(map, transform_nested_path_func), + tuple, + ), + xml_config, filter_key + ) + generate_filelist(file_install_list, 'filelist.csv') + # 先生成再检查,有利于问题定位 + if package_check: + check_filelist(file_install_list, check_features, check_move) + + +def get_pkg_xml_relative_path(pkg_args: Namespace) -> str: + """获取包配置文件相对路径。""" + + def parts(): + yield CONFIG_SCRIPT_PATH + yield pkg_args.pkg_name + if pkg_args.chip_scenes: + yield pkg_args.chip_scenes + # 可以通過build_rule指定xml_file,而且优先级高于默认值 + if pkg_args.xml_file: + yield pkg_args.xml_file + else: + yield f'{pkg_args.pkg_name}.xml' + + return os.path.join(*parts()) + + +def write_config_inc_var(name: str, package_attr: Dict, file: TextIO): + """向config.inc文件写入变量。""" + if name in package_attr: + value = str(package_attr[name]).lower() + file.write(f"{name.upper()}={value}\n") + + +def generate_config_inc(package_attr: Dict): + """生成config.inc文件。""" + if 'parallel' not in package_attr and 'parallel_limit' not in package_attr and 'use_move' not in package_attr: + return + year = datetime.now(timezone.utc).year + config_inc = os.path.join(TOP_DIR, "build", 'config.inc') + header = [ + '#!/bin/sh\n', + '#----------------------------------------------------------------------------\n', + f'# Copyright Huawei Technologies Co., Ltd. 2023-{year}. All rights reserved.\n', + '#----------------------------------------------------------------------------\n', + '\n', + ] + if os.path.isfile(config_inc): + os.chmod(config_inc, 0o700) + with open(config_inc, 'w', encoding='utf-8') as file: + file.writelines(header) + write_config_inc_var('parallel', package_attr, file) + write_config_inc_var('parallel_limit', package_attr, file) + write_config_inc_var('use_move', package_attr, file) + + os.chmod(config_inc, 0o500) + + +def main(pkg_name='', xml_file='', main_args=None): + """ + 功能描述: 执行打包流程(解析配置--->生成文件列表--->执行拷贝/打包动作) + 参数: pkg_name, os_arch, type + 返回值: SUCCESS/FAIL + """ + delivery_dir = os.path.join(TOP_DIR, DELIVERY_PATH) + if not os.path.exists(delivery_dir): + return FAIL + + config_relative_path = get_pkg_xml_relative_path(main_args) + pkg_xml_file = os.path.join(pkg_utils.TOP_SOURCE_DIR, config_relative_path) + parse_option = make_parse_option(main_args) + + try: + xml_config = parse_xml_config( + pkg_xml_file, delivery_dir, parse_option, main_args + ) + except ContainAsteriskError as ex: + CommLog.cilog_error(f"Value contain '*' in {config_relative_path}. value is '{ex.value}'.") + return FAIL + + if pkg_name in ['driver', 'firmware']: + filter_key = ['all', 'docker'] + elif pkg_name in ['aicpu_kernels_device', 'aicpu_kernels_host']: + filter_key = [] + else: + filter_key = ['all', 'run'] + + # 生成filelist.csv安装列表文件 + try: + generate_filelist_file_by_xml_config( + xml_config, filter_key, + main_args.package_check or xml_config.package_attr.get('package_check') + ) + except PackageNameEmptyError: + CommLog.cilog_error(f'package name is empty in {xml_file}, please check it') + return FAIL + except GenerateFilelistError as ex: + CommLog.cilog_error(f'generate filelist {ex.filename} failed!', ) + return FAIL + except FilelistError as ex: + CommLog.cilog_error('check filelist error! %s', str(ex)) + return FAIL + + generate_config_inc(xml_config.package_attr) + + package_option = PackageOption( + main_args.os_arch, main_args.package_suffix, main_args.not_in_name, main_args.pkg_version, main_args.ext_name, + chip_name=main_args.chip_name, func_name=main_args.func_name, version_dir=main_args.version_dir, + disable_multi_version=main_args.disable_multi_version, suffix=main_args.suffix) + + package_name = PackageName(xml_config.package_attr, main_args, xml_config.version) + + # 检查install_path与pkg_inner_softlink路径是否冲突,若冲突则报错 + if check_path_is_conflict(xml_config) == FAIL: + return FAIL + + # 生成打包命令 + return execute_repack_process(xml_config, delivery_dir, main_args, + package_name=package_name, package_option=package_option) + + +def args_parse(): + """ + 功能描述 : 脚本入参解析 + 参数 : 调用脚本的传参 + 返回值 : 解析后的参数值 + """ + parser = argparse.ArgumentParser( + description='This script is for package repack processing.') + parser.add_argument('-c', '--chip_scenes', metavar='chip_scenes', required=False, dest='chip_scenes', nargs='?', + const='', + default='', help='This parameter define chip id for package.') + parser.add_argument('-n', '--pkg_name', metavar='pkg_name', required=False, + help='This parameter define pkg_name for config_xml.') + parser.add_argument('-o', '--os_arch', metavar='os_arch', required=False, dest='os_arch', nargs='?', const='', + default=None, help="This parameter define the package's os_arch") + parser.add_argument('-t', '--type', metavar='type', required=False, dest='type', nargs='?', const='', + default='repack', help="This parameter define this script's function") + parser.add_argument('-i', '--not_in_name', metavar='not_in_name', required=False, dest='not_in_name', nargs='?', + const='', + default='', help="This parameter define the package's name not contain the element") + parser.add_argument('-v', '--pkg_version', metavar='pkg_version', required=False, dest='pkg_version', nargs='?', + const='', + default='', help="This parameter define the version for package.") + parser.add_argument('-e', '--ext_name', metavar='ext_name', required=False, dest='ext_name', nargs='?', const='', + default='', help="This parameter define the package's ext_name") + parser.add_argument('--package_suffix', nargs='?', const='none', + default='none', help="This parameter define the package suffix, debug or none") + parser.add_argument('--suffix', metavar='suffix', required=False, dest='suffix', nargs='?', const='', + default=None, help="This parameter define the package suffix, for example such as tar.gz") + parser.add_argument('-b', '--build_type', metavar='build_type', required=False, dest='build_type', nargs='?', + const='', + default='debug', help="This parameter define release type of package") + parser.add_argument('-x', '--xml', metavar='xml_file', required=False, dest='xml_file', nargs='?', const='', + default='', help="This parameter define xml file") + parser.add_argument('--chip_name', metavar='chip_name', required=False, dest='chip_name', nargs='?', const=None, + default=None, + help="This parameter define package chip name, has higher priority than chip name in xml") + parser.add_argument('--func_name', metavar='func_name', required=False, dest='func_name', nargs='?', const=None, + default=None, + help="This parameter define package func name, has higher priority than func name in xml") + parser.add_argument('--source_root', metavar='source_root', required=False, dest='source_root', nargs='?', const='', + help='source root dir.') + parser.add_argument('--version_dir', nargs='?', const='', default='', help='Set version dir.') + parser.add_argument('--tag', metavar='tag', nargs='?', const='', default='') + parser.add_argument('--disable-multi-version', action='store_true', help='Disable multi version.') + # 检查打包配置 + parser.add_argument('--package-check', action='store_true', help='check package config.') + parser.add_argument('--check_size', nargs='?', const='', default='', help="Check the size of a file or directory.") + parser.add_argument('--pkg-name-style', metavar='pkg_name_style', default='common', help='Package name style.') + return parser.parse_args() + + +if __name__ == "__main__": + CommLog.cilog_info("%s", " ".join(sys.argv)) + args = args_parse() + try: + if args.source_root: + pkg_utils.TOP_SOURCE_DIR = args.source_root + if args.build_type == '': + args.build_type = 'debug' + else: + args.build_type = args.build_type.lower() + status = main(args.pkg_name, args.xml_file, main_args=args) + except Exception as e: + CommLog.cilog_error("exception is occurred (%s)!", e) + CommLog.cilog_info("%s", traceback.format_exc()) + status = FAIL + sys.exit(status) diff --git a/version.info b/version.info new file mode 100644 index 0000000000000000000000000000000000000000..bb2a42aa4e0460b33c8a0b52cd7142ded2d78814 --- /dev/null +++ b/version.info @@ -0,0 +1,11 @@ +Version=8.5.0.alpha001 +version_dir=8.5.0.alpha001 +required_package_amct_acl_version=">=8.3" +required_package_aoe_version=">=8.3" +required_package_compiler_version=">=8.3" +required_package_fwkplugin_version=">=8.3" +required_package_hccl_version=">=8.3" +required_package_nca_version=">=8.3" +required_package_ncs_version=">=8.3" +required_package_runtime_version=">=8.3" +required_package_toolkit_version=">=8.3"