diff --git a/src/azure-cli-core/azure/cli/core/aaz/__init__.py b/src/azure-cli-core/azure/cli/core/aaz/__init__.py index 6c53627cc6b..23ae61bf70a 100644 --- a/src/azure-cli-core/azure/cli/core/aaz/__init__.py +++ b/src/azure-cli-core/azure/cli/core/aaz/__init__.py @@ -13,7 +13,7 @@ AAZFreeFormDictArg, AAZFloatArg, AAZBaseArg, AAZBoolArg, AAZListArg, AAZResourceGroupNameArg, \ AAZResourceLocationArg, AAZResourceIdArg, AAZSubscriptionIdArg, AAZUuidArg, AAZDateArg, AAZTimeArg, \ AAZDateTimeArg, AAZDurationArg, AAZFileArg, AAZPasswordArg, AAZPaginationTokenArg, AAZPaginationLimitArg, \ - AAZAnyTypeArg + AAZAnyTypeArg, AAZFileUploadArg from ._arg_fmt import AAZStrArgFormat, AAZIntArgFormat, AAZFloatArgFormat, AAZBoolArgFormat, AAZObjectArgFormat, \ AAZDictArgFormat, AAZFreeFormDictArgFormat, AAZListArgFormat, AAZResourceLocationArgFormat, \ AAZResourceIdArgFormat, AAZSubscriptionIdArgFormat, AAZUuidFormat, AAZDateFormat, AAZTimeFormat, \ @@ -23,7 +23,7 @@ from ._command import AAZCommand, AAZWaitCommand, AAZCommandGroup, \ register_callback, register_command, register_command_group, load_aaz_command_table, link_helper from ._field_type import AAZIntType, AAZFloatType, AAZStrType, AAZBoolType, AAZDictType, AAZFreeFormDictType, \ - AAZListType, AAZObjectType, AAZIdentityObjectType, AAZAnyType + AAZListType, AAZObjectType, AAZIdentityObjectType, AAZAnyType, AAZFileUploadType from ._operation import AAZHttpOperation, AAZJsonInstanceUpdateOperation, AAZGenericInstanceUpdateOperation, \ AAZJsonInstanceDeleteOperation, AAZJsonInstanceCreateOperation from ._prompt import AAZPromptInput, AAZPromptPasswordInput diff --git a/src/azure-cli-core/azure/cli/core/aaz/_arg.py b/src/azure-cli-core/azure/cli/core/aaz/_arg.py index 3c81dc9111b..4806f20f46a 100644 --- a/src/azure-cli-core/azure/cli/core/aaz/_arg.py +++ b/src/azure-cli-core/azure/cli/core/aaz/_arg.py @@ -14,10 +14,11 @@ from knack.log import get_logger from ._arg_action import AAZSimpleTypeArgAction, AAZObjectArgAction, AAZDictArgAction, \ - AAZListArgAction, AAZGenericUpdateAction, AAZGenericUpdateForceStringAction, AAZAnyTypeArgAction + AAZListArgAction, AAZGenericUpdateAction, AAZGenericUpdateForceStringAction, AAZAnyTypeArgAction, \ + AAZFileUploadTypeArgAction from ._base import AAZBaseType, AAZUndefined from ._field_type import AAZObjectType, AAZStrType, AAZIntType, AAZBoolType, AAZFloatType, AAZListType, AAZDictType, \ - AAZSimpleType, AAZFreeFormDictType, AAZAnyType + AAZSimpleType, AAZFreeFormDictType, AAZAnyType, AAZFileUploadType from ._field_value import AAZObject from ._arg_fmt import AAZObjectArgFormat, AAZListArgFormat, AAZDictArgFormat, AAZFreeFormDictArgFormat, \ AAZSubscriptionIdArgFormat, AAZResourceLocationArgFormat, AAZResourceIdArgFormat, AAZUuidFormat, AAZDateFormat, \ @@ -599,6 +600,20 @@ def __init__(self, fmt=None, **kwargs): super().__init__(fmt=fmt, **kwargs) +class AAZFileUploadArg(AAZStrArg, AAZFileUploadType): + """Argument that accepts a file path and returns file content, file hander and file size""" + + @property + def _type_in_help(self): + return "File Content" + + def _build_cmd_action(self): + class Action(AAZFileUploadTypeArgAction): + _schema = self # bind action class with current schema + + return Action + + # Generic Update arguments class AAZGenericUpdateForceStringArg(AAZBoolArg): diff --git a/src/azure-cli-core/azure/cli/core/aaz/_arg_action.py b/src/azure-cli-core/azure/cli/core/aaz/_arg_action.py index 5537ee3766b..7933468f30d 100644 --- a/src/azure-cli-core/azure/cli/core/aaz/_arg_action.py +++ b/src/azure-cli-core/azure/cli/core/aaz/_arg_action.py @@ -249,6 +249,33 @@ def format_data(cls, data): return data +class AAZFileUploadTypeArgAction(AAZArgAction): + + @classmethod + def setup_operations(cls, dest_ops, values, prefix_keys=None): + if values is None: + data = AAZBlankArgValue # use blank data when values string is None + else: + data = values + data = cls.format_data(data) + dest_ops.add(data) + + @classmethod + def format_data(cls, data): + if data == AAZBlankArgValue: + if cls._schema._blank == AAZUndefined: + raise AAZInvalidValueError("argument value cannot be blank") + data = copy.deepcopy(cls._schema._blank) + + if data is None: + if cls._schema._nullable: + return data + raise AAZInvalidValueError("field is not nullable") + if not os.path.exists(data): + raise AAZInvalidValueError(f"File '{data}' doesn't exist") + return data + + class AAZCompoundTypeArgAction(AAZArgAction): # pylint: disable=abstract-method @classmethod diff --git a/src/azure-cli-core/azure/cli/core/aaz/_field_type.py b/src/azure-cli-core/azure/cli/core/aaz/_field_type.py index 4638d108ecd..aa94d2a3c24 100644 --- a/src/azure-cli-core/azure/cli/core/aaz/_field_type.py +++ b/src/azure-cli-core/azure/cli/core/aaz/_field_type.py @@ -9,7 +9,7 @@ from azure.cli.core.util import shell_safe_json_parse from ._base import AAZBaseType, AAZValuePatch, AAZUndefined from ._field_value import AAZObject, AAZDict, AAZFreeFormDict, AAZList, AAZSimpleValue, \ - AAZIdentityObject, AAZAnyValue + AAZIdentityObject, AAZAnyValue, AAZFileUploadValue from ._utils import to_snack_case from .exceptions import AAZUnknownFieldError, AAZConflictFieldDefinitionError, AAZValuePrecisionLossError, \ AAZInvalidFieldError, AAZInvalidValueError @@ -111,6 +111,10 @@ def process_data(self, data, **kwargs): return data +class AAZFileUploadType(AAZStrType): + _ValueCls = AAZFileUploadValue + + class AAZAnyType(AAZSimpleType): """Any type""" diff --git a/src/azure-cli-core/azure/cli/core/aaz/_field_value.py b/src/azure-cli-core/azure/cli/core/aaz/_field_value.py index 69857bd61a6..407540d9808 100644 --- a/src/azure-cli-core/azure/cli/core/aaz/_field_value.py +++ b/src/azure-cli-core/azure/cli/core/aaz/_field_value.py @@ -5,6 +5,7 @@ # pylint: disable=protected-access from ._base import AAZBaseValue, AAZValuePatch, AAZUndefined import abc +import os class AAZSimpleValue(AAZBaseValue): @@ -59,6 +60,21 @@ class AAZAnyValue(AAZSimpleValue): # pylint: disable=too-few-public-methods pass +class AAZFileUploadValue(AAZSimpleValue): # pylint: disable=too-few-public-methods + + def to_serialized_data(self, processor=None, **kwargs): + _file_size = os.path.getsize(self._data) + _content = None + _file_handle = open(self._data, "rb") + if _file_size < 5 * 1024 * 1024: # 5MB + _content = _file_handle.read() + _file_handle.close() + _file_handle = None + return _content, _file_handle, _file_size + + return _content, _file_handle, _file_size + + class AAZObject(AAZBaseValue): def __init__(self, schema, data):