init v0.23.0

Signed-off-by: Sun Ruoxi <sunruoxi@4paradigm.com>
This commit is contained in:
2026-08-27 15:11:51 +08:00
parent b582a8e7d1
commit 7f8a1b1f7a
2849 changed files with 712887 additions and 22001 deletions

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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.
# -----------------------------------------------------------------------------------------------------------

View File

@@ -0,0 +1,2 @@
CUSTOM_DATA_PATH=$HOME/Ascend/latest/data/
CUSTOM_CONF_PATH=$HOME/Ascend/latest/conf/

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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.
# -----------------------------------------------------------------------------------------------------------

View File

@@ -0,0 +1,515 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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 collections import Counter
from collections.abc import Callable, Iterator
from enum import IntEnum
from functools import partial
from itertools import chain, repeat
from operator import and_, attrgetter, contains, itemgetter, lt, methodcaller, ne, not_
from typing import NamedTuple
from .utils.comm_log import CommLog
from .utils.funcbase import any_, constant, dispatch, identity, invoke, pipe, side_effect, star_apply
from .utils.pkg_utils import (
TOP_DIR,
FilelistError,
GenerateFilelistError,
conditional_apply,
config_feature_to_string,
pairwise,
swap_args,
)
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:
"""是否为相对路径。"""
return not path.startswith("/")
def is_specific_operations(file_item: FileItem, operations: list[str]) -> bool:
"""是否为特定的操作类型。"""
return file_item.operation in operations
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
return bool(item_install_types & install_types)
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

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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.
# -----------------------------------------------------------------------------------------------------------
"""合并算子binary_info_config.json。"""
import argparse
import json
import os
import sys
def load_json_file(json_file: str):
"""加载json文件。"""
with open(json_file, encoding="utf-8") as file:
json_content = json.load(file)
return json_content
def save_json_file(output_file: str, content):
"""保存json文件。"""
output_dir = os.path.dirname(output_file)
if not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
with open(output_file, "w", encoding="utf-8") as file:
json.dump(content, file, ensure_ascii=True, indent=2)
def update_config(base_content, update_content):
"""更新配置。"""
new_content = base_content.copy()
new_content.update(update_content)
return dict(sorted(new_content.items()))
def parse_args(argv: list[str]):
"""入参解析。"""
parser = argparse.ArgumentParser()
parser.add_argument("--base-file", required=True, help="the basic binary_info_config file")
parser.add_argument("--update-file", required=True, help="the update binary_info_config file")
parser.add_argument(
"--output-file", required=True, type=os.path.realpath, help="the output binary_info_config file"
)
args = parser.parse_args(argv)
return args
def main(argv: list[str]) -> bool:
"""主流程。"""
args = parse_args(argv)
base_content = load_json_file(args.base_file)
update_content = load_json_file(args.update_file)
result = update_config(base_content, update_content)
save_json_file(args.output_file, result)
return True
if __name__ == "__main__":
if not main(sys.argv[1:]): # pragma: no cover
sys.exit(1) # pragma: no cover

View File

@@ -0,0 +1,240 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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 shutil
import subprocess
from argparse import Namespace
from collections.abc import Callable
from itertools import chain
from subprocess import PIPE, STDOUT
from typing import NamedTuple
from .utils.comm_log import CommLog
from .utils.pkg_utils import CompressError
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) -> str | None:
"""获取属性。"""
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
makeself_tool: str | None = None
makeself_header: str | None = None
help_info: str | None = None
source_target: str | None = None
install_script: str | None = None
independent_pkg: bool | None = False
cleanup: str | None = None
def remove_ascend(text):
if text is None:
return None
text_lower = text.lower()
if text_lower == "ascend910_93":
return "A3"
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 following 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 []
independent_pkg = params.independent_pkg
compress_tool = get_compress_tool()
tar_format = get_compress_format()
if independent_pkg:
commands = chain(
[
"TMPDIR=$pwd",
params.makeself_tool,
"--header",
params.makeself_header,
"--help-header",
params.help_info,
compress_tool,
"--complevel",
"4",
"--nomd5",
"--sha256",
"--nooverwrite",
"--chown",
"--tar-format",
tar_format,
"--tar-extra",
"--numeric-owner",
"--tar-quietly",
],
get_cleanup_commands(),
[params.source_target, params.package_name, params.comments, params.install_script],
)
else:
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(
source_target: str, package_name: str, comments: str
) -> Callable[[str, dict, bool], MakeselfPkgParams]:
"""创建Makeself打包参数工厂。"""
def create_makeself_pkg_params(makeself_dir: str, package_attr: dict, independent_pkg=False) -> MakeselfPkgParams:
"""创建Makeself打包参数。"""
cleanup = package_attr.get("cleanup")
if independent_pkg:
install_script = str(package_attr.get("install_script"))
help_info = str(package_attr.get("help"))
makeself_tool = os.path.join(makeself_dir, "makeself.sh")
makeself_header = os.path.join(makeself_dir, "makeself-header.sh")
params = MakeselfPkgParams(
package_name=package_name,
comments=comments,
makeself_tool=makeself_tool,
makeself_header=makeself_header,
help_info=help_info,
source_target=source_target,
install_script=install_script,
independent_pkg=independent_pkg,
cleanup=cleanup,
)
else:
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[str | None, str | None]:
"""
功能描述: 组装打run包命令
返回值: command
"""
return compose_makeself_command(params), None
def exec_pack_cmd(delivery_dir: str, pack_cmd: str, package_name: str) -> str:
"""执行打包命令"""
if delivery_dir:
cmd = f"cd {delivery_dir} && {pack_cmd}"
else:
cmd = pack_cmd
CommLog.cilog_info("package cmd:%s", cmd)
result = subprocess.run(cmd, shell=True, check=False, stdout=PIPE, stderr=STDOUT)
output = result.stdout.decode()
if result.returncode != 0:
CommLog.cilog_error(__file__, "compress package(%s) failed! %s.", package_name, output)
raise CompressError(package_name)
return package_name

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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 inspect
import logging
import time
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

View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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 collections.abc import Callable, Iterator
from typing import 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_)

View File

@@ -0,0 +1,181 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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 collections.abc import Callable, Iterator
from itertools import chain, tee
from pathlib import Path
from typing import Optional, TypeVar
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: str | None):
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))

View File

@@ -0,0 +1,435 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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 xml.etree.ElementTree as ET
from functools import total_ordering
from pathlib import Path
from typing import NamedTuple
import regex as re
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]
return input_str.count(",") <= 1
@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:
raise AssertionError("should not go here.")
if input_str[-1] == "]":
high_type = 0
elif input_str[-1] == ")":
high_type = 1
else:
raise AssertionError("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 = f"{operator}{self.low.value.version}"
result.append(required_str)
if self.high:
if self.high.type_ == 0:
operator = "<="
else:
operator = "<"
required_str = f"{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 = f'required_package_{self.pkg_name}_version="{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: 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: VersionXml | None, disable_multi_version: bool, version_dir: str | None) -> str | None:
"""获取版本目录名。"""
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: dict[str, str] | None
itf_versions: list[str]
version: str
version_xml: VersionXml | None
timestamp: str | None
class VersionInfoFile(NamedTuple):
"""生成的版本配置。"""
version: str
itf_version_info: str | None = None
requires: list[Require] | None = None
version_dir: str | None = None
timestamp: str | None = None
def _get_content(self) -> str:
"""获取版本配置内容。"""
lines = [f"Version={self.version}"]
if self.version_dir:
lines.append(f"version_dir={self.version_dir}")
if self.timestamp:
lines.append(f"timestamp={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: 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)

View File

@@ -0,0 +1,281 @@
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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) {
require_arr[1] = substr(require_arr[1], pos + RLENGTH)
return check_compatible_lt(version_arr, len_version_arr, require_arr, len_require_arr)
}
return check_compatible_eq(version_arr, len_version_arr, require_arr, len_require_arr)
}
BEGIN {
len_all_required_arr = split(all_required, all_required_arr, ",")
compated = 0
in_gt = 0
matched_gt = 0
len_version_arr = split(version, version_arr, ".")
for (i = 1; i <= len_all_required_arr; i++) {
all_required_arr[i] = strip(all_required_arr[i])
one_compated = check_compatible(version_arr, len_version_arr, all_required_arr[i])
pos = match(all_required_arr[i], /^>/)
if (pos != 0) {
gt_require = 1
lt_require = 0
eq_require = 0
} else {
pos = match(all_required_arr[i], /^</)
if (pos != 0) {
gt_require = 0
lt_require = 1
eq_require = 0
} else {
gt_require = 0
lt_require = 0
eq_require = 1
}
}
if (matched_gt) {
if (one_compated) {
# gt after gt, all compated.
if (gt_require) {
matched_gt = 1
in_gt = 1
continue
}
# lt after gt, all compated.
if (lt_require) {
compated = 1
matched_gt = 0
in_gt = 0
break
}
# eq after gt, all compated.
if (eq_require) {
# eq compated, go.
compated = 1
break
}
} else {
# miscompated.
# gt after gt, compated first gt. miscompated second gt.
if (gt_require) {
matched_gt = 0
in_gt = 1
continue
}
# lt after gt, compated first gt. miscompated second lt.
if (lt_require) {
matched_gt = 0
in_gt = 0
continue
}
# eq after gt, compated first gt. miscompated second eq.
if (eq_require) {
continue
}
}
} else {
if (one_compated) {
if (gt_require) {
matched_gt = 1
in_gt = 1
continue
}
if (lt_require) {
if (in_gt) {
matched_gt = 0
in_gt = 0
continue
} else {
compated = 1
break
}
}
if (eq_require) {
# eq compated, go.
compated = 1
break
}
} else {
# miscompated.
if (gt_require) {
matched_gt = 0
in_gt = 1
continue
}
if (lt_require) {
matched_gt = 0
in_gt = 0
continue
}
if (eq_require) {
continue
}
}
}
}
if (matched_gt) {
compated = 1
}
if (compated == 0) {
printf("F")
} else {
printf("T")
}
}

View File

@@ -0,0 +1,14 @@
#!/bin/sh
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
#!/bin/sh
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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
}

View File

@@ -0,0 +1,37 @@
#!/bin/csh
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env fish
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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

View File

@@ -0,0 +1,61 @@
#!/bin/sh
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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.7 3.8 3.9 3.10 3.11 3.12"
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.7.x, Python3.8.x, Python3.9.x, Python3.10.x, Python3.11.x, Python3.12.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
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,305 @@
#!/bin/sh
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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
if [ "${USE_SHARE_INFO}" == "y" ]; then
ext_params="$ext_params --use-share-info"
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
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}
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
# 删除临时文件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
return ${total_ret}
}

View File

@@ -0,0 +1,469 @@
#!/bin/sh
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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 "\<ASCEND_HOME_PATH\>" "${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 <path>
__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
}
# 为bash添加rc配置
add_bash_env_rc() {
local userpath="$1"
local username="$2"
local usergroup="$3"
local path_regex="$4"
local setenv_filepath="$5"
local config_path="${userpath}/.bashrc"
local ret
__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
}
# 为fish添加rc配置
add_fish_env_rc() {
local userpath="$1"
local username="$2"
local usergroup="$3"
local path_regex="$4"
local setenv_filepath="$5"
local config_path="${userpath}/.config/fish/config.fish"
local ret
__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
}
# 为csh添加rc配置
add_csh_env_rc() {
local userpath="$1"
local username="$2"
local usergroup="$3"
local path_regex="$4"
local setenv_filepath="$5"
local config_path="${userpath}/.cshrc"
local ret
__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
}
# 添加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}"
case "${shell_type}" in
bash) add_bash_env_rc "${userpath}" "${username}" "${usergroup}" "${path_regex}" "${setenv_filepath}" ;;
fish) add_fish_env_rc "${userpath}" "${username}" "${usergroup}" "${path_regex}" "${setenv_filepath}" ;;
csh) add_csh_env_rc "${userpath}" "${username}" "${usergroup}" "${path_regex}" "${setenv_filepath}" ;;
esac
ret="$?" && [ $ret -ne 0 ] && return $ret
fi
# 如果bin目录不存在,则不处理
[ ! -d "${install_path}/bin" ] && return 0
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}\""
}
# 设置环境变量
add_setenv() {
return 0
}
# 删除环境变量
del_setenv() {
return 0
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
#!/bin/sh
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# 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_package_compat_version() {
local _outvar="$1"
local _version_info_path="$2"
local _result
if [ ! -f "${_version_info_path}" ]; then
read -r "$_outvar" <<EOF
EOF
return 1
fi
read -r "$_outvar" <<EOF
$(grep "^Version=" "$_version_info_path" | cut -d= -f2- | cut -d- -f1 | cut -d. -f-3)
EOF
}
# 获取正式包名
get_formal_package_name() {
local _outvar="$1"
local _package="$2"
read -r "$_outvar" <<EOF
$(echo "$_package" | sed 's/_/-/g')
EOF
}
# 获取非正式包名
get_informal_package_name() {
local _outvar="$1"
local _package="$2"
read -r "$_outvar" <<EOF
$(echo "$_package" | sed 's/-/_/g')
EOF
}
# 获取需求包列表。
_get_required_packages() {
local _version_info_path="$1"
if [ ! -f "$_version_info_path" ]; then
return 0
fi
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 ""
}
/^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, "_")
print package_name
}
' "${_version_info_path}"
}
# 获取需求包信息。
_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 src_pkg="$4"
local dst_pkg="$5"
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
echo "Version compatibility check failed, $src_pkg required $dst_pkg version $require, but $dst_pkg version is $version!"
return 1
}
# 检查版本兼容性。
_check_version_compatiable() {
local package="$1"
local install_path="$2"
local script_dir="$3"
local version_info_path="$script_dir/../version.info"
local err_msgs package_formal self_version src_pkg src_pkg_formal dst_pkg dst_pkg_formal
local installed_version_info pkg_version_info_path
get_formal_package_name "package_formal" "$package"
get_package_compat_version "self_version" "$version_info_path"
if [ -d "$install_path/share/info" ]; then
err_msgs="$(
ls "$install_path/share/info" | grep -v "^${package}$" | while read src_pkg; do
get_formal_package_name "src_pkg_formal" "$package"
installed_version_info="$install_path/share/info/$src_pkg/version.info"
grep "^required_package_${package_formal}_version=" "$installed_version_info" | cut -d= -f2- | tr -d '"' | while read required; do
_check_version_required "$self_version" "$required" "$script_dir" "$src_pkg_formal" "$package_formal"
done
done
)"
if [ "$err_msgs" != "" ]; then
while read err_msg; do
comm_log "ERROR" "$err_msg"
done <<EOF
$err_msgs
EOF
return 1
fi
fi
err_msgs="$(
_get_required_packages "${version_info_path}" | while read dst_pkg_formal; do
get_informal_package_name "dst_pkg" "$dst_pkg_formal"
pkg_version_info_path="$install_path/share/info/$dst_pkg_formal/version.info"
if [ ! -f "$pkg_version_info_path" ]; then
pkg_version_info_path="$install_path/share/info/$dst_pkg/version.info"
fi
if [ -f "$pkg_version_info_path" ]; then
get_package_compat_version "pkg_version" "$pkg_version_info_path"
_get_required_package_info "required" "$version_info_path" "$dst_pkg_formal"
_check_version_required "$pkg_version" "$required" "$script_dir" "$package_formal" "$dst_pkg_formal"
fi
done
)"
if [ "$err_msgs" != "" ]; then
while read err_msg; do
comm_log "ERROR" "$err_msg"
done <<EOF
$err_msgs
EOF
return 1
fi
return 0
}