From 5915556a1646c59e0012cf1e5836235a1ad5f286 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 2 May 2025 12:56:58 -0700 Subject: [PATCH 1/8] Initial v14 against current blob-tsp def --- .../src/clients/blob_client.rs | 14 +- .../src/clients/blob_container_client.rs | 11 +- .../src/clients/blob_service_client.rs | 5 +- .../src/clients/block_blob_client.rs | 14 +- .../azure_storage_blob/src/clients/mod.rs | 4 + .../generated/clients/append_blob_client.rs | 14 +- .../src/generated/clients/blob_client.rs | 24 ++- .../clients/blob_container_client.rs | 157 ++++++++++---- .../generated/clients/blob_service_client.rs | 103 +++++---- .../generated/clients/block_blob_client.rs | 35 ++- .../src/generated/clients/page_blob_client.rs | 12 +- .../src/generated/models/crate_models.rs | 80 ------- .../src/generated/models/header_traits.rs | 202 ++++++++++-------- .../src/generated/models/method_options.rs | 128 ++++++----- .../src/generated/models/mod.rs | 1 - .../src/generated/models/models_serde.rs | 16 +- .../src/generated/models/pub_models.rs | 37 ++-- .../src/generated/models/xml_helpers.rs | 18 +- sdk/storage/azure_storage_blob/src/lib.rs | 32 ++- .../azure_storage_blob/tests/blob_client.rs | 8 +- .../tests/blob_container_client.rs | 6 +- .../tests/blob_service_client.rs | 2 +- .../azure_storage_blob/tsp-location.yaml | 2 +- .../azure_storage_blob_test/src/lib.rs | 10 + 24 files changed, 530 insertions(+), 405 deletions(-) delete mode 100644 sdk/storage/azure_storage_blob/src/generated/models/crate_models.rs diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs index bd76a614cc..cf0a42c751 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs @@ -8,13 +8,15 @@ use crate::{ BlockBlobClientCommitBlockListResult, BlockBlobClientStageBlockResult, BlockBlobClientUploadResult, }, - models::{AccessTier, BlockList, BlockListType, BlockLookupList}, + models::{ + AccessTier, BlobClientDeleteOptions, BlobClientDownloadOptions, + BlobClientGetPropertiesOptions, BlobClientSetMetadataOptions, + BlobClientSetPropertiesOptions, BlobClientSetTierOptions, + BlockBlobClientCommitBlockListOptions, BlockBlobClientUploadOptions, BlockList, + BlockListType, BlockLookupList, + }, pipeline::StorageHeadersPolicy, - BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientGetPropertiesOptions, - BlobClientOptions, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, - BlobClientSetTierOptions, BlockBlobClient, BlockBlobClientCommitBlockListOptions, - BlockBlobClientGetBlockListOptions, BlockBlobClientStageBlockOptions, - BlockBlobClientUploadOptions, + BlobClientOptions, BlockBlobClient, }; use azure_core::{ credentials::TokenCredential, diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs index f66ff7a67b..e09ff48034 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs @@ -3,10 +3,13 @@ use crate::{ generated::clients::BlobContainerClient as GeneratedBlobContainerClient, - generated::models::BlobContainerClientGetPropertiesResult, pipeline::StorageHeadersPolicy, - BlobClient, BlobClientOptions, BlobContainerClientCreateOptions, - BlobContainerClientDeleteOptions, BlobContainerClientGetPropertiesOptions, - BlobContainerClientOptions, BlobContainerClientSetMetadataOptions, + generated::models::BlobContainerClientGetPropertiesResult, + models::{ + BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, + BlobContainerClientGetPropertiesOptions, BlobContainerClientSetMetadataOptions, + }, + pipeline::StorageHeadersPolicy, + BlobClient, BlobContainerClientOptions, }; use azure_core::{ credentials::TokenCredential, diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs index bfb1d9a345..9f593c9ec7 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs @@ -3,8 +3,9 @@ use crate::{ generated::clients::BlobServiceClient as GeneratedBlobServiceClient, - models::StorageServiceProperties, pipeline::StorageHeadersPolicy, BlobContainerClient, - BlobContainerClientOptions, BlobServiceClientGetPropertiesOptions, BlobServiceClientOptions, + models::{BlobServiceClientGetPropertiesOptions, StorageServiceProperties}, + pipeline::StorageHeadersPolicy, + BlobContainerClient, BlobServiceClientOptions, }; use azure_core::{ credentials::TokenCredential, diff --git a/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs index cd58b28848..a1d88f2694 100644 --- a/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs @@ -8,13 +8,15 @@ use crate::{ BlockBlobClientCommitBlockListResult, BlockBlobClientStageBlockResult, BlockBlobClientUploadResult, }, - models::{BlockList, BlockListType, BlockLookupList, StorageServiceProperties}, + models::{ + BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientGetPropertiesOptions, + BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTierOptions, + BlockBlobClientCommitBlockListOptions, BlockBlobClientGetBlockListOptions, + BlockBlobClientStageBlockOptions, BlockBlobClientUploadOptions, BlockList, BlockListType, + BlockLookupList, StorageServiceProperties, + }, pipeline::StorageHeadersPolicy, - BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientGetPropertiesOptions, - BlobClientOptions, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, - BlobClientSetTierOptions, BlockBlobClientCommitBlockListOptions, - BlockBlobClientGetBlockListOptions, BlockBlobClientOptions, BlockBlobClientStageBlockOptions, - BlockBlobClientUploadOptions, + BlobClientOptions, BlockBlobClientOptions, }; use azure_core::{ credentials::TokenCredential, diff --git a/sdk/storage/azure_storage_blob/src/clients/mod.rs b/sdk/storage/azure_storage_blob/src/clients/mod.rs index 6398608579..2b9367ae2e 100644 --- a/sdk/storage/azure_storage_blob/src/clients/mod.rs +++ b/sdk/storage/azure_storage_blob/src/clients/mod.rs @@ -12,3 +12,7 @@ pub use blob_client::BlobClient; pub use blob_container_client::BlobContainerClient; pub use blob_service_client::BlobServiceClient; pub use block_blob_client::BlockBlobClient; + +pub use crate::generated::clients::{ + BlobClientOptions, BlobContainerClientOptions, BlobServiceClientOptions, BlockBlobClientOptions, +}; diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs index 29c089ddfd..b9dc3e7e94 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs @@ -119,7 +119,7 @@ impl AppendBlobClient { request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); if let Some(transactional_content_md5) = options.transactional_content_md5 { - request.insert_header("content-md5", transactional_content_md5); + request.insert_header("content-md5", base64::encode(transactional_content_md5)); } request.insert_header("content-type", "application/octet-stream"); if let Some(if_match) = options.if_match { @@ -147,7 +147,10 @@ impl AppendBlobClient { request.insert_header("x-ms-client-request-id", client_request_id); } if let Some(transactional_content_crc64) = options.transactional_content_crc64 { - request.insert_header("x-ms-content-crc64", transactional_content_crc64); + request.insert_header( + "x-ms-content-crc64", + base64::encode(transactional_content_crc64), + ); } if let Some(encryption_algorithm) = options.encryption_algorithm { request.insert_header( @@ -216,7 +219,7 @@ impl AppendBlobClient { request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); if let Some(transactional_content_md5) = options.transactional_content_md5 { - request.insert_header("content-md5", transactional_content_md5); + request.insert_header("content-md5", base64::encode(transactional_content_md5)); } request.insert_header("content-type", "application/xml"); if let Some(if_match) = options.if_match { @@ -275,7 +278,10 @@ impl AppendBlobClient { ); } if let Some(source_content_md5) = options.source_content_md5 { - request.insert_header("x-ms-source-content-md5", source_content_md5); + request.insert_header( + "x-ms-source-content-md5", + base64::encode(source_content_md5), + ); } if let Some(source_if_match) = options.source_if_match { request.insert_header("x-ms-source-if-match", source_if_match); diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs index a2790d6fe3..02e3d89730 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs @@ -265,10 +265,12 @@ impl BlobClient { /// /// * `lease_id` - Required. A lease ID for the source path. If specified, the source path must have an active lease and the /// lease ID must match. + /// * `proposed_lease_id` - Required. The proposed lease ID for the container. /// * `options` - Optional parameters for the request. pub async fn change_lease( &self, lease_id: String, + proposed_lease_id: String, options: Option>, ) -> Result> { let options = options.unwrap_or_default(); @@ -310,9 +312,7 @@ impl BlobClient { request.insert_header("x-ms-if-tags", if_tags); } request.insert_header("x-ms-lease-id", lease_id); - if let Some(proposed_lease_id) = options.proposed_lease_id { - request.insert_header("x-ms-proposed-lease-id", proposed_lease_id); - } + request.insert_header("x-ms-proposed-lease-id", proposed_lease_id); request.insert_header("x-ms-version", &self.version); self.pipeline.send(&ctx, &mut request).await } @@ -374,7 +374,7 @@ impl BlobClient { request.insert_header("x-ms-copy-source-authorization", copy_source_authorization); } if let Some(copy_source_tags) = options.copy_source_tags { - request.insert_header("x-ms-copy-source-tags", copy_source_tags); + request.insert_header("x-ms-copy-source-tag-option", copy_source_tags); } if let Some(encryption_scope) = options.encryption_scope { request.insert_header("x-ms-encryption-scope", encryption_scope); @@ -406,7 +406,10 @@ impl BlobClient { } } if let Some(source_content_md5) = options.source_content_md5 { - request.insert_header("x-ms-source-content-md5", source_content_md5); + request.insert_header( + "x-ms-source-content-md5", + base64::encode(source_content_md5), + ); } if let Some(source_if_match) = options.source_if_match { request.insert_header("x-ms-source-if-match", source_if_match); @@ -695,6 +698,9 @@ impl BlobClient { range_get_content_md5.to_string(), ); } + if let Some(structured_body_type) = options.structured_body_type { + request.insert_header("x-ms-structured-body", structured_body_type); + } request.insert_header("x-ms-version", &self.version); self.pipeline.send(&ctx, &mut request).await } @@ -1296,14 +1302,17 @@ impl BlobClient { let mut request = Request::new(url, Method::Put); request.insert_header("accept", "application/json"); if let Some(transactional_content_md5) = options.transactional_content_md5 { - request.insert_header("content-md5", transactional_content_md5); + request.insert_header("content-md5", base64::encode(transactional_content_md5)); } request.insert_header("content-type", "application/xml"); if let Some(client_request_id) = options.client_request_id { request.insert_header("x-ms-client-request-id", client_request_id); } if let Some(transactional_content_crc64) = options.transactional_content_crc64 { - request.insert_header("x-ms-content-crc64", transactional_content_crc64); + request.insert_header( + "x-ms-content-crc64", + base64::encode(transactional_content_crc64), + ); } if let Some(if_tags) = options.if_tags { request.insert_header("x-ms-if-tags", if_tags); @@ -1387,7 +1396,6 @@ impl BlobClient { path = path.replace("{blobName}", &self.blob_name); path = path.replace("{containerName}", &self.container_name); url = url.join(&path)?; - url.query_pairs_mut().append_pair("comp", "copy"); if let Some(timeout) = options.timeout { url.query_pairs_mut() .append_pair("timeout", &timeout.to_string()); diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs index 788cdd7263..efa44f3924 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs @@ -30,9 +30,10 @@ use azure_core::{ fmt::SafeDebug, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - ClientOptions, Context, Method, Pipeline, Request, RequestContent, Response, Url, + ClientOptions, Context, Method, Pager, PagerResult, Pipeline, Request, RequestContent, + Response, Url, }, - Result, + xml, Result, }; use std::sync::Arc; @@ -491,20 +492,21 @@ impl BlobContainerClient { /// # Arguments /// /// * `options` - Optional parameters for the request. - pub async fn list_blob_flat_segment( + pub fn list_blob_flat_segment( &self, options: Option>, - ) -> Result> { - let options = options.unwrap_or_default(); - let ctx = Context::with_context(&options.method_options.context); - let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; - url.query_pairs_mut() + ) -> Result> { + let options = options.unwrap_or_default().into_owned(); + let pipeline = self.pipeline.clone(); + let mut first_url = self.endpoint.clone(); + first_url = first_url.join(&self.container_name)?; + first_url + .query_pairs_mut() .append_pair("comp", "list") .append_key_only("flat") .append_pair("restype", "container"); if let Some(include) = options.include { - url.query_pairs_mut().append_pair( + first_url.query_pairs_mut().append_pair( "include", &include .iter() @@ -514,27 +516,60 @@ impl BlobContainerClient { ); } if let Some(marker) = options.marker { - url.query_pairs_mut().append_pair("marker", &marker); + first_url.query_pairs_mut().append_pair("marker", &marker); } if let Some(maxresults) = options.maxresults { - url.query_pairs_mut() + first_url + .query_pairs_mut() .append_pair("maxresults", &maxresults.to_string()); } if let Some(prefix) = options.prefix { - url.query_pairs_mut().append_pair("prefix", &prefix); + first_url.query_pairs_mut().append_pair("prefix", &prefix); } if let Some(timeout) = options.timeout { - url.query_pairs_mut() + first_url + .query_pairs_mut() .append_pair("timeout", &timeout.to_string()); } - let mut request = Request::new(url, Method::Get); - request.insert_header("accept", "application/xml"); - request.insert_header("content-type", "application/xml"); - if let Some(client_request_id) = options.client_request_id { - request.insert_header("x-ms-client-request-id", client_request_id); - } - request.insert_header("x-ms-version", &self.version); - self.pipeline.send(&ctx, &mut request).await + let version = self.version.clone(); + Ok(Pager::from_callback(move |marker: Option| { + let mut url = first_url.clone(); + if let Some(marker) = marker { + if url.query_pairs().any(|(name, _)| name.eq("marker")) { + let mut new_url = url.clone(); + new_url + .query_pairs_mut() + .clear() + .extend_pairs(url.query_pairs().filter(|(name, _)| name.ne("marker"))); + url = new_url; + } + url.query_pairs_mut().append_pair("marker", &marker); + } + let mut request = Request::new(url, Method::Get); + request.insert_header("accept", "application/xml"); + request.insert_header("content-type", "application/xml"); + if let Some(client_request_id) = &options.client_request_id { + request.insert_header("x-ms-client-request-id", client_request_id); + } + request.insert_header("x-ms-version", &version); + let ctx = options.method_options.context.clone(); + let pipeline = pipeline.clone(); + async move { + let rsp: Response = + pipeline.send(&ctx, &mut request).await?; + let (status, headers, body) = rsp.deconstruct(); + let bytes = body.collect().await?; + let res: ListBlobsFlatSegmentResponse = xml::read_xml(&bytes)?; + let rsp = Response::from_bytes(status, headers, bytes); + Ok(match res.next_marker { + Some(next_marker) => PagerResult::Continue { + response: rsp, + continuation: next_marker, + }, + None => PagerResult::Complete { response: rsp }, + }) + } + })) } /// The List Blobs operation returns a list of the blobs under the specified container. A delimiter can be used to traverse @@ -546,22 +581,25 @@ impl BlobContainerClient { /// that acts as a placeholder for all blobs whose names begin with the same substring up to the appearance of the delimiter /// character. The delimiter may be a single character or a string. /// * `options` - Optional parameters for the request. - pub async fn list_blob_hierarchy_segment( + pub fn list_blob_hierarchy_segment( &self, delimiter: &str, options: Option>, - ) -> Result> { - let options = options.unwrap_or_default(); - let ctx = Context::with_context(&options.method_options.context); - let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; - url.query_pairs_mut() + ) -> Result> { + let options = options.unwrap_or_default().into_owned(); + let pipeline = self.pipeline.clone(); + let mut first_url = self.endpoint.clone(); + first_url = first_url.join(&self.container_name)?; + first_url + .query_pairs_mut() .append_pair("comp", "list") .append_key_only("hierarchy") .append_pair("restype", "container"); - url.query_pairs_mut().append_pair("delimiter", delimiter); + first_url + .query_pairs_mut() + .append_pair("delimiter", delimiter); if let Some(include) = options.include { - url.query_pairs_mut().append_pair( + first_url.query_pairs_mut().append_pair( "include", &include .iter() @@ -571,27 +609,60 @@ impl BlobContainerClient { ); } if let Some(marker) = options.marker { - url.query_pairs_mut().append_pair("marker", &marker); + first_url.query_pairs_mut().append_pair("marker", &marker); } if let Some(maxresults) = options.maxresults { - url.query_pairs_mut() + first_url + .query_pairs_mut() .append_pair("maxresults", &maxresults.to_string()); } if let Some(prefix) = options.prefix { - url.query_pairs_mut().append_pair("prefix", &prefix); + first_url.query_pairs_mut().append_pair("prefix", &prefix); } if let Some(timeout) = options.timeout { - url.query_pairs_mut() + first_url + .query_pairs_mut() .append_pair("timeout", &timeout.to_string()); } - let mut request = Request::new(url, Method::Get); - request.insert_header("accept", "application/xml"); - request.insert_header("content-type", "application/xml"); - if let Some(client_request_id) = options.client_request_id { - request.insert_header("x-ms-client-request-id", client_request_id); - } - request.insert_header("x-ms-version", &self.version); - self.pipeline.send(&ctx, &mut request).await + let version = self.version.clone(); + Ok(Pager::from_callback(move |marker: Option| { + let mut url = first_url.clone(); + if let Some(marker) = marker { + if url.query_pairs().any(|(name, _)| name.eq("marker")) { + let mut new_url = url.clone(); + new_url + .query_pairs_mut() + .clear() + .extend_pairs(url.query_pairs().filter(|(name, _)| name.ne("marker"))); + url = new_url; + } + url.query_pairs_mut().append_pair("marker", &marker); + } + let mut request = Request::new(url, Method::Get); + request.insert_header("accept", "application/xml"); + request.insert_header("content-type", "application/xml"); + if let Some(client_request_id) = &options.client_request_id { + request.insert_header("x-ms-client-request-id", client_request_id); + } + request.insert_header("x-ms-version", &version); + let ctx = options.method_options.context.clone(); + let pipeline = pipeline.clone(); + async move { + let rsp: Response = + pipeline.send(&ctx, &mut request).await?; + let (status, headers, body) = rsp.deconstruct(); + let bytes = body.collect().await?; + let res: ListBlobsHierarchySegmentResponse = xml::read_xml(&bytes)?; + let rsp = Response::from_bytes(status, headers, bytes); + Ok(match res.next_marker { + Some(next_marker) => PagerResult::Continue { + response: rsp, + continuation: next_marker, + }, + None => PagerResult::Complete { response: rsp }, + }) + } + })) } /// The Release Lease operation frees the lease if it's no longer needed, so that another client can immediately acquire a diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs index f96f1fdc61..82ea7905fe 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs @@ -6,12 +6,11 @@ use crate::generated::{ clients::BlobContainerClient, models::{ - crate_models::{GetUserDelegationKeyRequest, SetPropertiesRequest}, BlobServiceClientFilterBlobsOptions, BlobServiceClientGetAccountInfoOptions, BlobServiceClientGetAccountInfoResult, BlobServiceClientGetPropertiesOptions, BlobServiceClientGetStatisticsOptions, BlobServiceClientGetUserDelegationKeyOptions, BlobServiceClientListContainersSegmentOptions, BlobServiceClientSetPropertiesOptions, - FilterBlobSegment, ListContainersSegmentResponse, StorageServiceProperties, + FilterBlobSegment, KeyInfo, ListContainersSegmentResponse, StorageServiceProperties, StorageServiceStats, UserDelegationKey, }, }; @@ -20,9 +19,10 @@ use azure_core::{ fmt::SafeDebug, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - ClientOptions, Context, Method, Pipeline, Request, RequestContent, Response, Url, + ClientOptions, Context, Method, Pager, PagerResult, Pipeline, Request, RequestContent, + Response, Url, }, - Result, + xml, Result, }; use std::sync::Arc; @@ -240,13 +240,11 @@ impl BlobServiceClient { /// /// # Arguments /// - /// * `start` - The date-time the key is active. - /// * `expiry` - The date-time the key expires. + /// * `key_info` - Key information provided in the request /// * `options` - Optional parameters for the request. pub async fn get_user_delegation_key( &self, - start: String, - expiry: String, + key_info: RequestContent, options: Option>, ) -> Result> { let options = options.unwrap_or_default(); @@ -266,9 +264,7 @@ impl BlobServiceClient { request.insert_header("x-ms-client-request-id", client_request_id); } request.insert_header("x-ms-version", &self.version); - let body: RequestContent = - GetUserDelegationKeyRequest { start, expiry }.try_into()?; - request.set_body(body); + request.set_body(key_info); self.pipeline.send(&ctx, &mut request).await } @@ -277,16 +273,16 @@ impl BlobServiceClient { /// # Arguments /// /// * `options` - Optional parameters for the request. - pub async fn list_containers_segment( + pub fn list_containers_segment( &self, options: Option>, - ) -> Result> { - let options = options.unwrap_or_default(); - let ctx = Context::with_context(&options.method_options.context); - let mut url = self.endpoint.clone(); - url.query_pairs_mut().append_pair("comp", "list"); + ) -> Result> { + let options = options.unwrap_or_default().into_owned(); + let pipeline = self.pipeline.clone(); + let mut first_url = self.endpoint.clone(); + first_url.query_pairs_mut().append_pair("comp", "list"); if let Some(include) = options.include { - url.query_pairs_mut().append_pair( + first_url.query_pairs_mut().append_pair( "include", &include .iter() @@ -296,27 +292,60 @@ impl BlobServiceClient { ); } if let Some(marker) = options.marker { - url.query_pairs_mut().append_pair("marker", &marker); + first_url.query_pairs_mut().append_pair("marker", &marker); } if let Some(maxresults) = options.maxresults { - url.query_pairs_mut() + first_url + .query_pairs_mut() .append_pair("maxresults", &maxresults.to_string()); } if let Some(prefix) = options.prefix { - url.query_pairs_mut().append_pair("prefix", &prefix); + first_url.query_pairs_mut().append_pair("prefix", &prefix); } if let Some(timeout) = options.timeout { - url.query_pairs_mut() + first_url + .query_pairs_mut() .append_pair("timeout", &timeout.to_string()); } - let mut request = Request::new(url, Method::Get); - request.insert_header("accept", "application/xml"); - request.insert_header("content-type", "application/xml"); - if let Some(client_request_id) = options.client_request_id { - request.insert_header("x-ms-client-request-id", client_request_id); - } - request.insert_header("x-ms-version", &self.version); - self.pipeline.send(&ctx, &mut request).await + let version = self.version.clone(); + Ok(Pager::from_callback(move |marker: Option| { + let mut url = first_url.clone(); + if let Some(marker) = marker { + if url.query_pairs().any(|(name, _)| name.eq("marker")) { + let mut new_url = url.clone(); + new_url + .query_pairs_mut() + .clear() + .extend_pairs(url.query_pairs().filter(|(name, _)| name.ne("marker"))); + url = new_url; + } + url.query_pairs_mut().append_pair("marker", &marker); + } + let mut request = Request::new(url, Method::Get); + request.insert_header("accept", "application/xml"); + request.insert_header("content-type", "application/xml"); + if let Some(client_request_id) = &options.client_request_id { + request.insert_header("x-ms-client-request-id", client_request_id); + } + request.insert_header("x-ms-version", &version); + let ctx = options.method_options.context.clone(); + let pipeline = pipeline.clone(); + async move { + let rsp: Response = + pipeline.send(&ctx, &mut request).await?; + let (status, headers, body) = rsp.deconstruct(); + let bytes = body.collect().await?; + let res: ListContainersSegmentResponse = xml::read_xml(&bytes)?; + let rsp = Response::from_bytes(status, headers, bytes); + Ok(match res.next_marker { + Some(next_marker) => PagerResult::Continue { + response: rsp, + continuation: next_marker, + }, + None => PagerResult::Complete { response: rsp }, + }) + } + })) } /// Sets properties for a storage account's Blob service endpoint, including properties for Storage Analytics and CORS (Cross-Origin @@ -324,9 +353,11 @@ impl BlobServiceClient { /// /// # Arguments /// + /// * `storage_service_properties` - The storage service properties to set. /// * `options` - Optional parameters for the request. pub async fn set_properties( &self, + storage_service_properties: RequestContent, options: Option>, ) -> Result> { let options = options.unwrap_or_default(); @@ -346,17 +377,7 @@ impl BlobServiceClient { request.insert_header("x-ms-client-request-id", client_request_id); } request.insert_header("x-ms-version", &self.version); - let body: RequestContent = SetPropertiesRequest { - logging: options.logging, - hour_metrics: options.hour_metrics, - minute_metrics: options.minute_metrics, - cors: options.cors, - default_service_version: options.default_service_version, - delete_retention_policy: options.delete_retention_policy, - static_website: options.static_website, - } - .try_into()?; - request.set_body(body); + request.set_body(storage_service_properties); self.pipeline.send(&ctx, &mut request).await } } diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs index 1099b1e3c7..939ea27285 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs @@ -124,7 +124,7 @@ impl BlockBlobClient { let mut request = Request::new(url, Method::Put); request.insert_header("accept", "application/json"); if let Some(transactional_content_md5) = options.transactional_content_md5 { - request.insert_header("content-md5", transactional_content_md5); + request.insert_header("content-md5", base64::encode(transactional_content_md5)); } request.insert_header("content-type", "application/xml"); if let Some(if_match) = options.if_match { @@ -167,7 +167,10 @@ impl BlockBlobClient { request.insert_header("x-ms-client-request-id", client_request_id); } if let Some(transactional_content_crc64) = options.transactional_content_crc64 { - request.insert_header("x-ms-content-crc64", transactional_content_crc64); + request.insert_header( + "x-ms-content-crc64", + base64::encode(transactional_content_crc64), + ); } if let Some(encryption_algorithm) = options.encryption_algorithm { request.insert_header( @@ -299,7 +302,7 @@ impl BlockBlobClient { request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); if let Some(transactional_content_md5) = options.transactional_content_md5 { - request.insert_header("content-md5", transactional_content_md5); + request.insert_header("content-md5", base64::encode(transactional_content_md5)); } request.insert_header("content-type", "application/octet-stream"); if let Some(if_match) = options.if_match { @@ -353,7 +356,7 @@ impl BlockBlobClient { ); } if let Some(copy_source_tags) = options.copy_source_tags { - request.insert_header("x-ms-copy-source-tags", copy_source_tags); + request.insert_header("x-ms-copy-source-tag-option", copy_source_tags); } if let Some(encryption_algorithm) = options.encryption_algorithm { request.insert_header( @@ -382,7 +385,10 @@ impl BlockBlobClient { } } if let Some(source_content_md5) = options.source_content_md5 { - request.insert_header("x-ms-source-content-md5", source_content_md5); + request.insert_header( + "x-ms-source-content-md5", + base64::encode(source_content_md5), + ); } if let Some(source_if_match) = options.source_if_match { request.insert_header("x-ms-source-if-match", source_if_match); @@ -517,14 +523,17 @@ impl BlockBlobClient { request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); if let Some(transactional_content_md5) = options.transactional_content_md5 { - request.insert_header("content-md5", transactional_content_md5); + request.insert_header("content-md5", base64::encode(transactional_content_md5)); } request.insert_header("content-type", "application/octet-stream"); if let Some(client_request_id) = options.client_request_id { request.insert_header("x-ms-client-request-id", client_request_id); } if let Some(transactional_content_crc64) = options.transactional_content_crc64 { - request.insert_header("x-ms-content-crc64", transactional_content_crc64); + request.insert_header( + "x-ms-content-crc64", + base64::encode(transactional_content_crc64), + ); } if let Some(encryption_algorithm) = options.encryption_algorithm { request.insert_header( @@ -619,7 +628,10 @@ impl BlockBlobClient { ); } if let Some(source_content_md5) = options.source_content_md5 { - request.insert_header("x-ms-source-content-md5", source_content_md5); + request.insert_header( + "x-ms-source-content-md5", + base64::encode(source_content_md5), + ); } if let Some(source_if_match) = options.source_if_match { request.insert_header("x-ms-source-if-match", source_if_match); @@ -678,7 +690,7 @@ impl BlockBlobClient { request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); if let Some(transactional_content_md5) = options.transactional_content_md5 { - request.insert_header("content-md5", transactional_content_md5); + request.insert_header("content-md5", base64::encode(transactional_content_md5)); } request.insert_header("content-type", "application/octet-stream"); if let Some(if_match) = options.if_match { @@ -722,7 +734,10 @@ impl BlockBlobClient { request.insert_header("x-ms-client-request-id", client_request_id); } if let Some(transactional_content_crc64) = options.transactional_content_crc64 { - request.insert_header("x-ms-content-crc64", transactional_content_crc64); + request.insert_header( + "x-ms-content-crc64", + base64::encode(transactional_content_crc64), + ); } if let Some(encryption_algorithm) = options.encryption_algorithm { request.insert_header( diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs index 02c8bb9a83..d748bba9d0 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs @@ -683,7 +683,7 @@ impl PageBlobClient { request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); if let Some(transactional_content_md5) = options.transactional_content_md5 { - request.insert_header("content-md5", transactional_content_md5); + request.insert_header("content-md5", base64::encode(transactional_content_md5)); } request.insert_header("content-type", "application/octet-stream"); if let Some(if_match) = options.if_match { @@ -705,7 +705,10 @@ impl PageBlobClient { request.insert_header("x-ms-client-request-id", client_request_id); } if let Some(transactional_content_crc64) = options.transactional_content_crc64 { - request.insert_header("x-ms-content-crc64", transactional_content_crc64); + request.insert_header( + "x-ms-content-crc64", + base64::encode(transactional_content_crc64), + ); } if let Some(encryption_algorithm) = options.encryption_algorithm { request.insert_header( @@ -874,7 +877,10 @@ impl PageBlobClient { ); } if let Some(source_content_md5) = options.source_content_md5 { - request.insert_header("x-ms-source-content-md5", source_content_md5); + request.insert_header( + "x-ms-source-content-md5", + base64::encode(source_content_md5), + ); } if let Some(source_if_match) = options.source_if_match { request.insert_header("x-ms-source-if-match", source_if_match); diff --git a/sdk/storage/azure_storage_blob/src/generated/models/crate_models.rs b/sdk/storage/azure_storage_blob/src/generated/models/crate_models.rs deleted file mode 100644 index f2638eeada..0000000000 --- a/sdk/storage/azure_storage_blob/src/generated/models/crate_models.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the MIT License. See License.txt in the project root for license information. -// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. - -use super::{ - xml_helpers::CorsCorsRule, CorsRule, Logging, Metrics, RetentionPolicy, StaticWebsite, -}; -use azure_core::{fmt::SafeDebug, http::RequestContent, xml::to_xml, Result}; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] -pub(crate) struct GetUserDelegationKeyRequest { - /// The date-time the key expires. - #[serde(rename = "Expiry")] - pub(crate) expiry: String, - - /// The date-time the key is active. - #[serde(rename = "Start")] - pub(crate) start: String, -} - -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] -pub(crate) struct SetPropertiesRequest { - /// The CORS properties. - #[serde( - default, - deserialize_with = "CorsCorsRule::unwrap", - rename = "Cors", - serialize_with = "CorsCorsRule::wrap", - skip_serializing_if = "Option::is_none" - )] - pub(crate) cors: Option>, - - /// The default service version. - #[serde( - rename = "DefaultServiceVersion", - skip_serializing_if = "Option::is_none" - )] - pub(crate) default_service_version: Option, - - /// The delete retention policy. - #[serde( - rename = "DeleteRetentionPolicy", - skip_serializing_if = "Option::is_none" - )] - pub(crate) delete_retention_policy: Option, - - /// The hour metrics properties. - #[serde(rename = "HourMetrics", skip_serializing_if = "Option::is_none")] - pub(crate) hour_metrics: Option, - - /// The logging properties. - #[serde(rename = "Logging", skip_serializing_if = "Option::is_none")] - pub(crate) logging: Option, - - /// The minute metrics properties. - #[serde(rename = "MinuteMetrics", skip_serializing_if = "Option::is_none")] - pub(crate) minute_metrics: Option, - - /// The static website properties. - #[serde(rename = "StaticWebsite", skip_serializing_if = "Option::is_none")] - pub(crate) static_website: Option, -} - -impl TryFrom for RequestContent { - type Error = azure_core::Error; - fn try_from(value: GetUserDelegationKeyRequest) -> Result { - RequestContent::try_from(to_xml(&value)?) - } -} - -impl TryFrom for RequestContent { - type Error = azure_core::Error; - fn try_from(value: SetPropertiesRequest) -> Result { - RequestContent::try_from(to_xml(&value)?) - } -} diff --git a/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs b/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs index ac44727c08..cb132ce3a1 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs @@ -22,7 +22,7 @@ use super::{ BlockBlobClientCommitBlockListResult, BlockBlobClientPutBlobFromUrlResult, BlockBlobClientQueryResult, BlockBlobClientStageBlockFromUrlResult, BlockBlobClientStageBlockResult, BlockBlobClientUploadResult, BlockList, CopyStatus, - FilterBlobSegment, LeaseState, LeaseStatus, ListBlobsFlatSegmentResponse, + FilterBlobSegment, LeaseDuration, LeaseState, LeaseStatus, ListBlobsFlatSegmentResponse, ListBlobsHierarchySegmentResponse, PageBlobClientClearPagesResult, PageBlobClientCopyIncrementalResult, PageBlobClientCreateResult, PageBlobClientResizeResult, PageBlobClientUpdateSequenceNumberResult, PageBlobClientUploadPagesFromUrlResult, @@ -114,13 +114,13 @@ const VERSION_ID: HeaderName = HeaderName::from_static("x-ms-version-id"); /// Provides access to typed response headers for `AppendBlobClient::append_block_from_url()` pub trait AppendBlobClientAppendBlockFromUrlResultHeaders: private::Sealed { - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; fn blob_append_offset(&self) -> Result>; fn blob_committed_block_count(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; fn is_server_encrypted(&self) -> Result>; @@ -131,8 +131,8 @@ impl AppendBlobClientAppendBlockFromUrlResultHeaders { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -164,8 +164,10 @@ impl AppendBlobClientAppendBlockFromUrlResultHeaders } /// This response header is returned so that the client can check for the integrity of the copied content. - fn content_crc64(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted @@ -190,13 +192,13 @@ impl AppendBlobClientAppendBlockFromUrlResultHeaders /// Provides access to typed response headers for `AppendBlobClient::append_block()` pub trait AppendBlobClientAppendBlockResultHeaders: private::Sealed { - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; fn blob_append_offset(&self) -> Result>; fn blob_committed_block_count(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; fn is_server_encrypted(&self) -> Result>; @@ -206,8 +208,8 @@ pub trait AppendBlobClientAppendBlockResultHeaders: private::Sealed { impl AppendBlobClientAppendBlockResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -239,8 +241,10 @@ impl AppendBlobClientAppendBlockResultHeaders for Response Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted @@ -270,7 +274,7 @@ impl AppendBlobClientAppendBlockResultHeaders for Response Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; @@ -283,8 +287,8 @@ pub trait AppendBlobClientCreateResultHeaders: private::Sealed { impl AppendBlobClientCreateResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -472,11 +476,11 @@ impl BlobClientChangeLeaseResultHeaders for Response Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn copy_id(&self) -> Result>; fn copy_status(&self) -> Result>; fn encryption_scope(&self) -> Result>; @@ -486,8 +490,8 @@ pub trait BlobClientCopyFromUrlResultHeaders: private::Sealed { impl BlobClientCopyFromUrlResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -508,8 +512,10 @@ impl BlobClientCopyFromUrlResultHeaders for Response Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// String identifier for this copy operation. Use with Get Blob Properties to check the status of this copy operation, or @@ -606,7 +612,7 @@ pub trait BlobClientDownloadResultHeaders: private::Sealed { fn content_encoding(&self) -> Result>; fn content_language(&self) -> Result>; fn content_length(&self) -> Result>; - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn content_range(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; @@ -615,7 +621,7 @@ pub trait BlobClientDownloadResultHeaders: private::Sealed { fn is_sealed(&self) -> Result>; fn blob_sequence_number(&self) -> Result>; fn blob_type(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn copy_completion_time(&self) -> Result>; fn copy_id(&self) -> Result>; fn copy_progress(&self) -> Result>; @@ -629,7 +635,7 @@ pub trait BlobClientDownloadResultHeaders: private::Sealed { fn immutability_policy_expires_on(&self) -> Result>; fn is_current_version(&self) -> Result>; fn last_accessed(&self) -> Result>; - fn duration(&self) -> Result>; + fn duration(&self) -> Result>; fn lease_state(&self) -> Result>; fn lease_status(&self) -> Result>; fn legal_hold(&self) -> Result>; @@ -677,8 +683,8 @@ impl BlobClientDownloadResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// Indicates the range of bytes returned in the event that the client requested a subset of the blob by setting the 'Range' @@ -729,8 +735,10 @@ impl BlobClientDownloadResultHeaders for Response { } /// This response header is returned so that the client can check for the integrity of the copied content. - fn content_crc64(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// Conclusion time of the last attempted Copy Blob operation where this blob was the destination blob. This value can specify @@ -823,7 +831,7 @@ impl BlobClientDownloadResultHeaders for Response { /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease /// can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change. - fn duration(&self) -> Result> { + fn duration(&self) -> Result> { Headers::get_optional_as(self.headers(), &LEASE_DURATION) } @@ -928,7 +936,7 @@ pub trait BlobClientGetPropertiesResultHeaders: private::Sealed { fn content_encoding(&self) -> Result>; fn content_language(&self) -> Result>; fn content_length(&self) -> Result>; - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; fn tier(&self) -> Result>; @@ -955,7 +963,7 @@ pub trait BlobClientGetPropertiesResultHeaders: private::Sealed { fn is_incremental_copy(&self) -> Result>; fn is_current_version(&self) -> Result>; fn last_accessed(&self) -> Result>; - fn duration(&self) -> Result>; + fn duration(&self) -> Result>; fn lease_state(&self) -> Result>; fn lease_status(&self) -> Result>; fn legal_hold(&self) -> Result>; @@ -999,8 +1007,8 @@ impl BlobClientGetPropertiesResultHeaders for Response Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// The date/time that the container was last modified. @@ -1168,7 +1176,7 @@ impl BlobClientGetPropertiesResultHeaders for Response Result> { + fn duration(&self) -> Result> { Headers::get_optional_as(self.headers(), &LEASE_DURATION) } @@ -1590,7 +1598,7 @@ pub trait BlobContainerClientGetPropertiesResultHeaders: private::Sealed { fn has_immutability_policy(&self) -> Result>; fn has_legal_hold(&self) -> Result>; fn is_immutable_storage_with_versioning_enabled(&self) -> Result>; - fn duration(&self) -> Result>; + fn duration(&self) -> Result>; fn lease_state(&self) -> Result>; fn lease_status(&self) -> Result>; fn metadata(&self) -> Result>; @@ -1644,7 +1652,7 @@ impl BlobContainerClientGetPropertiesResultHeaders /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease /// can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change. - fn duration(&self) -> Result> { + fn duration(&self) -> Result> { Headers::get_optional_as(self.headers(), &LEASE_DURATION) } @@ -1829,10 +1837,10 @@ impl BlobTagsHeaders for Response { /// Provides access to typed response headers for `BlockBlobClient::commit_block_list()` pub trait BlockBlobClientCommitBlockListResultHeaders: private::Sealed { - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; fn is_server_encrypted(&self) -> Result>; @@ -1844,8 +1852,8 @@ impl BlockBlobClientCommitBlockListResultHeaders { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// The date/time that the container was last modified. @@ -1861,8 +1869,10 @@ impl BlockBlobClientCommitBlockListResultHeaders } /// This response header is returned so that the client can check for the integrity of the copied content. - fn content_crc64(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted @@ -1893,7 +1903,7 @@ impl BlockBlobClientCommitBlockListResultHeaders /// Provides access to typed response headers for `BlockBlobClient::put_blob_from_url()` pub trait BlockBlobClientPutBlobFromUrlResultHeaders: private::Sealed { - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; @@ -1906,8 +1916,8 @@ pub trait BlockBlobClientPutBlobFromUrlResultHeaders: private::Sealed { impl BlockBlobClientPutBlobFromUrlResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -1961,7 +1971,7 @@ pub trait BlockBlobClientQueryResultHeaders: private::Sealed { fn content_encoding(&self) -> Result>; fn content_language(&self) -> Result>; fn content_length(&self) -> Result>; - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn content_range(&self) -> Result>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; @@ -1970,7 +1980,7 @@ pub trait BlockBlobClientQueryResultHeaders: private::Sealed { fn blob_content_md5(&self) -> Result>>; fn blob_sequence_number(&self) -> Result>; fn blob_type(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn copy_completion_time(&self) -> Result>; fn copy_id(&self) -> Result>; fn copy_progress(&self) -> Result>; @@ -1979,7 +1989,7 @@ pub trait BlockBlobClientQueryResultHeaders: private::Sealed { fn copy_status_description(&self) -> Result>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; - fn duration(&self) -> Result>; + fn duration(&self) -> Result>; fn lease_state(&self) -> Result>; fn lease_status(&self) -> Result>; fn metadata(&self) -> Result>; @@ -2022,8 +2032,8 @@ impl BlockBlobClientQueryResultHeaders for Response /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// Indicates the range of bytes returned in the event that the client requested a subset of the blob by setting the 'Range' @@ -2074,8 +2084,10 @@ impl BlockBlobClientQueryResultHeaders for Response } /// This response header is returned so that the client can check for the integrity of the copied content. - fn content_crc64(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// Conclusion time of the last attempted Copy Blob operation where this blob was the destination blob. This value can specify @@ -2137,7 +2149,7 @@ impl BlockBlobClientQueryResultHeaders for Response /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease /// can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change. - fn duration(&self) -> Result> { + fn duration(&self) -> Result> { Headers::get_optional_as(self.headers(), &LEASE_DURATION) } @@ -2172,9 +2184,9 @@ impl BlockBlobClientQueryResultHeaders for Response /// Provides access to typed response headers for `BlockBlobClient::stage_block_from_url()` pub trait BlockBlobClientStageBlockFromUrlResultHeaders: private::Sealed { - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; fn is_server_encrypted(&self) -> Result>; @@ -2185,8 +2197,8 @@ impl BlockBlobClientStageBlockFromUrlResultHeaders { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -2195,8 +2207,10 @@ impl BlockBlobClientStageBlockFromUrlResultHeaders } /// This response header is returned so that the client can check for the integrity of the copied content. - fn content_crc64(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted @@ -2221,8 +2235,8 @@ impl BlockBlobClientStageBlockFromUrlResultHeaders /// Provides access to typed response headers for `BlockBlobClient::stage_block()` pub trait BlockBlobClientStageBlockResultHeaders: private::Sealed { - fn content_md5(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_md5(&self) -> Result>>; + fn content_crc64(&self) -> Result>>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; fn is_server_encrypted(&self) -> Result>; @@ -2231,13 +2245,15 @@ pub trait BlockBlobClientStageBlockResultHeaders: private::Sealed { impl BlockBlobClientStageBlockResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// This response header is returned so that the client can check for the integrity of the copied content. - fn content_crc64(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted @@ -2262,7 +2278,7 @@ impl BlockBlobClientStageBlockResultHeaders for Response Result>; + fn content_md5(&self) -> Result>>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; fn encryption_key_sha256(&self) -> Result>; @@ -2274,8 +2290,8 @@ pub trait BlockBlobClientUploadResultHeaders: private::Sealed { impl BlockBlobClientUploadResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// The date/time that the container was last modified. @@ -2383,19 +2399,19 @@ impl ListBlobsHierarchySegmentResponseHeaders for Response Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; fn blob_sequence_number(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; } impl PageBlobClientClearPagesResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -2421,8 +2437,10 @@ impl PageBlobClientClearPagesResultHeaders for Response Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } } @@ -2467,7 +2485,7 @@ impl PageBlobClientCopyIncrementalResultHeaders for Response Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; @@ -2480,8 +2498,8 @@ pub trait PageBlobClientCreateResultHeaders: private::Sealed { impl PageBlobClientCreateResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -2595,12 +2613,12 @@ impl PageBlobClientUpdateSequenceNumberResultHeaders /// Provides access to typed response headers for `PageBlobClient::upload_pages_from_url()` pub trait PageBlobClientUploadPagesFromUrlResultHeaders: private::Sealed { - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; fn blob_sequence_number(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; fn is_server_encrypted(&self) -> Result>; @@ -2611,8 +2629,8 @@ impl PageBlobClientUploadPagesFromUrlResultHeaders { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -2638,8 +2656,10 @@ impl PageBlobClientUploadPagesFromUrlResultHeaders } /// This response header is returned so that the client can check for the integrity of the copied content. - fn content_crc64(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted @@ -2664,12 +2684,12 @@ impl PageBlobClientUploadPagesFromUrlResultHeaders /// Provides access to typed response headers for `PageBlobClient::upload_pages()` pub trait PageBlobClientUploadPagesResultHeaders: private::Sealed { - fn content_md5(&self) -> Result>; + fn content_md5(&self) -> Result>>; fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; fn blob_sequence_number(&self) -> Result>; - fn content_crc64(&self) -> Result>; + fn content_crc64(&self) -> Result>>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; fn is_server_encrypted(&self) -> Result>; @@ -2679,8 +2699,8 @@ pub trait PageBlobClientUploadPagesResultHeaders: private::Sealed { impl PageBlobClientUploadPagesResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. - fn content_md5(&self) -> Result> { - Headers::get_optional_as(self.headers(), &CONTENT_MD5) + fn content_md5(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| base64::decode(h.as_str())) } /// UTC date/time value generated by the service that indicates the time at which the response was initiated @@ -2706,8 +2726,10 @@ impl PageBlobClientUploadPagesResultHeaders for Response Result> { - Headers::get_optional_as(self.headers(), &CONTENT_CRC64) + fn content_crc64(&self) -> Result>> { + Headers::get_optional_with(self.headers(), &CONTENT_CRC64, |h| { + base64::decode(h.as_str()) + }) } /// The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted diff --git a/sdk/storage/azure_storage_blob/src/generated/models/method_options.rs b/sdk/storage/azure_storage_blob/src/generated/models/method_options.rs index 8ae7e61e18..2a52a8bd63 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/method_options.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/method_options.rs @@ -4,10 +4,9 @@ // Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. use super::{ - AccessTier, BlobDeleteType, BlobImmutabilityPolicyMode, CorsRule, DeleteSnapshotsOptionType, - EncryptionAlgorithmType, FilterBlobsIncludeItem, ListBlobsIncludeItem, - ListContainersIncludeType, Logging, Metrics, PremiumPageBlobAccessTier, PublicAccessType, - RehydratePriority, RetentionPolicy, StaticWebsite, + AccessTier, BlobDeleteType, BlobImmutabilityPolicyMode, DeleteSnapshotsOptionType, + EncryptionAlgorithmType, FilterBlobsIncludeItem, LeaseDuration, ListBlobsIncludeItem, + ListContainersIncludeType, PremiumPageBlobAccessTier, PublicAccessType, RehydratePriority, }; use azure_core::{fmt::SafeDebug, http::ClientMethodOptions}; use std::collections::HashMap; @@ -78,11 +77,11 @@ pub struct AppendBlobClientAppendBlockOptions<'a> { pub timeout: Option, /// Specify the transactional crc64 for the body, to be validated by the service. - pub transactional_content_crc64: Option, + pub transactional_content_crc64: Option>, /// Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks /// were validated when each was uploaded. - pub transactional_content_md5: Option, + pub transactional_content_md5: Option>, } /// Options to be passed to `AppendBlobClient::append_block_from_url()` @@ -146,7 +145,7 @@ pub struct AppendBlobClientAppendBlockFromUrlOptions<'a> { pub source_content_crc64: Option>, /// Specify the md5 calculated for the range of bytes that must be read from the copy source. - pub source_content_md5: Option, + pub source_content_md5: Option>, /// Specify an ETag value to operate only on blobs with a matching value. pub source_if_match: Option, @@ -168,7 +167,7 @@ pub struct AppendBlobClientAppendBlockFromUrlOptions<'a> { /// Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks /// were validated when each was uploaded. - pub transactional_content_md5: Option, + pub transactional_content_md5: Option>, } /// Options to be passed to `AppendBlobClient::create()` @@ -314,7 +313,7 @@ pub struct BlobClientAcquireLeaseOptions<'a> { /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease /// can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change. - pub duration: Option, + pub duration: Option, /// The request should only proceed if an entity matches this string. pub if_match: Option, @@ -400,9 +399,6 @@ pub struct BlobClientChangeLeaseOptions<'a> { /// Allows customization of the method call. pub method_options: ClientMethodOptions<'a>, - /// Optional. The proposed lease ID for the container. - pub proposed_lease_id: Option, - /// The timeout parameter is expressed in seconds. For more information, see [Setting Timeouts for Blob Service Operations.](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations) pub timeout: Option, } @@ -460,7 +456,7 @@ pub struct BlobClientCopyFromUrlOptions<'a> { pub method_options: ClientMethodOptions<'a>, /// Specify the md5 calculated for the range of bytes that must be read from the copy source. - pub source_content_md5: Option, + pub source_content_md5: Option>, /// Specify an ETag value to operate only on blobs with a matching value. pub source_if_match: Option, @@ -654,6 +650,9 @@ pub struct BlobClientDownloadOptions<'a> { /// information on working with blob snapshots, see [Creating a Snapshot of a Blob.](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob) pub snapshot: Option, + /// Required if the request body is a structured message. Specifies the message schema version and properties. + pub structured_body_type: Option, + /// The timeout parameter is expressed in seconds. For more information, see [Setting Timeouts for Blob Service Operations.](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations) pub timeout: Option, @@ -1001,11 +1000,11 @@ pub struct BlobClientSetTagsOptions<'a> { pub timeout: Option, /// Specify the transactional crc64 for the body, to be validated by the service. - pub transactional_content_crc64: Option, + pub transactional_content_crc64: Option>, /// Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks /// were validated when each was uploaded. - pub transactional_content_md5: Option, + pub transactional_content_md5: Option>, /// The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate /// on. It's for service version 2019-10-10 and newer. @@ -1135,7 +1134,7 @@ pub struct BlobContainerClientAcquireLeaseOptions<'a> { /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease /// can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change. - pub duration: Option, + pub duration: Option, /// A date-time value. A request is made under the condition that the resource has been modified since the specified date-time. pub if_modified_since: Option, @@ -1350,6 +1349,22 @@ pub struct BlobContainerClientListBlobFlatSegmentOptions<'a> { pub timeout: Option, } +impl BlobContainerClientListBlobFlatSegmentOptions<'_> { + pub fn into_owned(self) -> BlobContainerClientListBlobFlatSegmentOptions<'static> { + BlobContainerClientListBlobFlatSegmentOptions { + client_request_id: self.client_request_id, + include: self.include, + marker: self.marker, + maxresults: self.maxresults, + method_options: ClientMethodOptions { + context: self.method_options.context.into_owned(), + }, + prefix: self.prefix, + timeout: self.timeout, + } + } +} + /// Options to be passed to `BlobContainerClient::list_blob_hierarchy_segment()` #[derive(Clone, Default, SafeDebug)] pub struct BlobContainerClientListBlobHierarchySegmentOptions<'a> { @@ -1379,6 +1394,22 @@ pub struct BlobContainerClientListBlobHierarchySegmentOptions<'a> { pub timeout: Option, } +impl BlobContainerClientListBlobHierarchySegmentOptions<'_> { + pub fn into_owned(self) -> BlobContainerClientListBlobHierarchySegmentOptions<'static> { + BlobContainerClientListBlobHierarchySegmentOptions { + client_request_id: self.client_request_id, + include: self.include, + marker: self.marker, + maxresults: self.maxresults, + method_options: ClientMethodOptions { + context: self.method_options.context.into_owned(), + }, + prefix: self.prefix, + timeout: self.timeout, + } + } +} + /// Options to be passed to `BlobContainerClient::release_lease()` #[derive(Clone, Default, SafeDebug)] pub struct BlobContainerClientReleaseLeaseOptions<'a> { @@ -1609,36 +1640,31 @@ pub struct BlobServiceClientListContainersSegmentOptions<'a> { pub timeout: Option, } +impl BlobServiceClientListContainersSegmentOptions<'_> { + pub fn into_owned(self) -> BlobServiceClientListContainersSegmentOptions<'static> { + BlobServiceClientListContainersSegmentOptions { + client_request_id: self.client_request_id, + include: self.include, + marker: self.marker, + maxresults: self.maxresults, + method_options: ClientMethodOptions { + context: self.method_options.context.into_owned(), + }, + prefix: self.prefix, + timeout: self.timeout, + } + } +} + /// Options to be passed to `BlobServiceClient::set_properties()` #[derive(Clone, Default, SafeDebug)] pub struct BlobServiceClientSetPropertiesOptions<'a> { /// An opaque, globally-unique, client-generated string identifier for the request. pub client_request_id: Option, - /// The CORS properties. - pub cors: Option>, - - /// The default service version. - pub default_service_version: Option, - - /// The delete retention policy. - pub delete_retention_policy: Option, - - /// The hour metrics properties. - pub hour_metrics: Option, - - /// The logging properties. - pub logging: Option, - /// Allows customization of the method call. pub method_options: ClientMethodOptions<'a>, - /// The minute metrics properties. - pub minute_metrics: Option, - - /// The static website properties. - pub static_website: Option, - /// The timeout parameter is expressed in seconds. For more information, see [Setting Timeouts for Blob Service Operations.](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations) pub timeout: Option, } @@ -1732,11 +1758,11 @@ pub struct BlockBlobClientCommitBlockListOptions<'a> { pub timeout: Option, /// Specify the transactional crc64 for the body, to be validated by the service. - pub transactional_content_crc64: Option, + pub transactional_content_crc64: Option>, /// Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks /// were validated when each was uploaded. - pub transactional_content_md5: Option, + pub transactional_content_md5: Option>, } /// Options to be passed to `BlockBlobClient::get_block_list()` @@ -1845,7 +1871,7 @@ pub struct BlockBlobClientPutBlobFromUrlOptions<'a> { pub method_options: ClientMethodOptions<'a>, /// Specify the md5 calculated for the range of bytes that must be read from the copy source. - pub source_content_md5: Option, + pub source_content_md5: Option>, /// Specify an ETag value to operate only on blobs with a matching value. pub source_if_match: Option, @@ -1870,7 +1896,7 @@ pub struct BlockBlobClientPutBlobFromUrlOptions<'a> { /// Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks /// were validated when each was uploaded. - pub transactional_content_md5: Option, + pub transactional_content_md5: Option>, } /// Options to be passed to `BlockBlobClient::query()` @@ -1954,11 +1980,11 @@ pub struct BlockBlobClientStageBlockOptions<'a> { pub timeout: Option, /// Specify the transactional crc64 for the body, to be validated by the service. - pub transactional_content_crc64: Option, + pub transactional_content_crc64: Option>, /// Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks /// were validated when each was uploaded. - pub transactional_content_md5: Option, + pub transactional_content_md5: Option>, } /// Options to be passed to `BlockBlobClient::stage_block_from_url()` @@ -1997,7 +2023,7 @@ pub struct BlockBlobClientStageBlockFromUrlOptions<'a> { pub source_content_crc64: Option>, /// Specify the md5 calculated for the range of bytes that must be read from the copy source. - pub source_content_md5: Option, + pub source_content_md5: Option>, /// Specify an ETag value to operate only on blobs with a matching value. pub source_if_match: Option, @@ -2107,11 +2133,11 @@ pub struct BlockBlobClientUploadOptions<'a> { pub timeout: Option, /// Specify the transactional crc64 for the body, to be validated by the service. - pub transactional_content_crc64: Option, + pub transactional_content_crc64: Option>, /// Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks /// were validated when each was uploaded. - pub transactional_content_md5: Option, + pub transactional_content_md5: Option>, } /// Options to be passed to `PageBlobClient::clear_pages()` @@ -2228,8 +2254,8 @@ pub struct PageBlobClientCreateOptions<'a> { /// Optional. Sets the blob's content type. If specified, this property is stored with the blob and returned with a read request. pub blob_content_type: Option, - /// Optional. The sequence number is a user-controlled property that you can use to track requests. The value of the sequence - /// number must be between 0 and 2^63 - 1. The default value is 0. + /// Set for page blobs only. The sequence number is a user-controlled value that you can use to track requests. The value + /// of the sequence number must be between 0 and 2^63 - 1. pub blob_sequence_number: Option, /// Optional. Used to set blob tags in various blob operations. @@ -2551,11 +2577,11 @@ pub struct PageBlobClientUploadPagesOptions<'a> { pub timeout: Option, /// Specify the transactional crc64 for the body, to be validated by the service. - pub transactional_content_crc64: Option, + pub transactional_content_crc64: Option>, /// Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks /// were validated when each was uploaded. - pub transactional_content_md5: Option, + pub transactional_content_md5: Option>, } /// Options to be passed to `PageBlobClient::upload_pages_from_url()` @@ -2618,7 +2644,7 @@ pub struct PageBlobClientUploadPagesFromUrlOptions<'a> { pub source_content_crc64: Option>, /// Specify the md5 calculated for the range of bytes that must be read from the copy source. - pub source_content_md5: Option, + pub source_content_md5: Option>, /// Specify an ETag value to operate only on blobs with a matching value. pub source_if_match: Option, diff --git a/sdk/storage/azure_storage_blob/src/generated/models/mod.rs b/sdk/storage/azure_storage_blob/src/generated/models/mod.rs index 46fdc8994b..097f968604 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/mod.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/mod.rs @@ -11,6 +11,5 @@ pub use enums::*; pub use header_traits::*; pub use method_options::*; pub use pub_models::*; -pub(crate) mod crate_models; pub(crate) mod models_serde; pub(crate) mod xml_helpers; diff --git a/sdk/storage/azure_storage_blob/src/generated/models/models_serde.rs b/sdk/storage/azure_storage_blob/src/generated/models/models_serde.rs index 1a67b79a64..ceb5acde6f 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/models_serde.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/models_serde.rs @@ -3,7 +3,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. // Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. -use super::{BlobTags, BlockLookupList, QueryRequest}; +use super::{BlobTags, BlockLookupList, KeyInfo, QueryRequest, StorageServiceProperties}; use azure_core::{http::RequestContent, xml::to_xml, Result}; impl TryFrom for RequestContent { @@ -20,6 +20,13 @@ impl TryFrom for RequestContent { } } +impl TryFrom for RequestContent { + type Error = azure_core::Error; + fn try_from(value: KeyInfo) -> Result { + RequestContent::try_from(to_xml(&value)?) + } +} + impl TryFrom for RequestContent { type Error = azure_core::Error; fn try_from(value: QueryRequest) -> Result { @@ -27,6 +34,13 @@ impl TryFrom for RequestContent { } } +impl TryFrom for RequestContent { + type Error = azure_core::Error; + fn try_from(value: StorageServiceProperties) -> Result { + RequestContent::try_from(to_xml(&value)?) + } +} + pub mod option_vec_encoded_bytes_std { #![allow(clippy::type_complexity)] use azure_core::base64; diff --git a/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs b/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs index 4a4403d42d..67199a0d6a 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs @@ -222,10 +222,9 @@ pub struct BlobFlatListSegment { default, deserialize_with = "Blob_itemsBlob::unwrap", rename = "BlobItems", - serialize_with = "Blob_itemsBlob::wrap", - skip_serializing_if = "Option::is_none" + serialize_with = "Blob_itemsBlob::wrap" )] - pub blob_items: Option>, + pub blob_items: Vec, } /// Represents an array of blobs. @@ -239,10 +238,9 @@ pub struct BlobHierarchyListSegment { default, deserialize_with = "Blob_itemsBlob::unwrap", rename = "BlobItems", - serialize_with = "Blob_itemsBlob::wrap", - skip_serializing_if = "Option::is_none" + serialize_with = "Blob_itemsBlob::wrap" )] - pub blob_items: Option>, + pub blob_items: Vec, /// The blob prefixes. #[serde( @@ -971,6 +969,19 @@ pub struct JsonTextConfiguration { pub record_separator: Option, } +/// Key information +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[typespec(format = "xml")] +pub struct KeyInfo { + /// The date-time the key expires. + #[serde(rename = "Expiry", skip_serializing_if = "Option::is_none")] + pub expiry: Option, + + /// The date-time the key is active. + #[serde(rename = "Start", skip_serializing_if = "Option::is_none")] + pub start: Option, +} + /// An enumeration of blobs. #[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] #[non_exhaustive] @@ -998,8 +1009,8 @@ pub struct ListBlobsFlatSegmentResponse { pub prefix: Option, /// The blob segment. - #[serde(skip_serializing_if = "Option::is_none")] - pub segment: Option, + #[serde(default)] + pub segment: BlobFlatListSegment, /// The service endpoint. #[serde(rename = "@ServiceEndpoint", skip_serializing_if = "Option::is_none")] @@ -1037,8 +1048,8 @@ pub struct ListBlobsHierarchySegmentResponse { pub prefix: Option, /// The blob segment. - #[serde(skip_serializing_if = "Option::is_none")] - pub segment: Option, + #[serde(default)] + pub segment: BlobHierarchyListSegment, /// The service endpoint. #[serde(rename = "@ServiceEndpoint", skip_serializing_if = "Option::is_none")] @@ -1056,10 +1067,9 @@ pub struct ListContainersSegmentResponse { default, deserialize_with = "Container_itemsContainer::unwrap", rename = "Containers", - serialize_with = "Container_itemsContainer::wrap", - skip_serializing_if = "Option::is_none" + serialize_with = "Container_itemsContainer::wrap" )] - pub container_items: Option>, + pub container_items: Vec, /// The marker of the containers. #[serde(rename = "Marker", skip_serializing_if = "Option::is_none")] @@ -1342,7 +1352,6 @@ pub struct StaticWebsite { /// The service properties. #[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[non_exhaustive] #[typespec(format = "xml")] pub struct StorageServiceProperties { /// The CORS properties. diff --git a/sdk/storage/azure_storage_blob/src/generated/models/xml_helpers.rs b/sdk/storage/azure_storage_blob/src/generated/models/xml_helpers.rs index af85d4a115..f20d4a15ef 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/xml_helpers.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/xml_helpers.rs @@ -16,21 +16,18 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[serde(rename = "BlobItems")] pub(crate) struct Blob_itemsBlob { #[serde(default)] - Blob: Option>, + Blob: Vec, } impl Blob_itemsBlob { - pub fn unwrap<'de, D>(deserializer: D) -> Result>, D::Error> + pub fn unwrap<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { Ok(Blob_itemsBlob::deserialize(deserializer)?.Blob) } - pub fn wrap( - to_serialize: &Option>, - serializer: S, - ) -> Result + pub fn wrap(to_serialize: &Vec, serializer: S) -> Result where S: Serializer, { @@ -178,21 +175,18 @@ impl Committed_blocksBlock { #[serde(rename = "Containers")] pub(crate) struct Container_itemsContainer { #[serde(default)] - Container: Option>, + Container: Vec, } impl Container_itemsContainer { - pub fn unwrap<'de, D>(deserializer: D) -> Result>, D::Error> + pub fn unwrap<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { Ok(Container_itemsContainer::deserialize(deserializer)?.Container) } - pub fn wrap( - to_serialize: &Option>, - serializer: S, - ) -> Result + pub fn wrap(to_serialize: &Vec, serializer: S) -> Result where S: Serializer, { diff --git a/sdk/storage/azure_storage_blob/src/lib.rs b/sdk/storage/azure_storage_blob/src/lib.rs index ec64004b2d..b0e83f0e00 100644 --- a/sdk/storage/azure_storage_blob/src/lib.rs +++ b/sdk/storage/azure_storage_blob/src/lib.rs @@ -11,28 +11,22 @@ pub mod clients; mod generated; mod pipeline; -pub use crate::clients::{BlobClient, BlobContainerClient, BlobServiceClient, BlockBlobClient}; -pub use crate::generated::clients::{ - BlobClientOptions, BlobContainerClientOptions, BlobServiceClientOptions, BlockBlobClientOptions, -}; -pub use crate::generated::models::{ - BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientGetPropertiesOptions, - BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTierOptions, - BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, - BlobContainerClientGetPropertiesOptions, BlobContainerClientSetMetadataOptions, - BlobServiceClientGetPropertiesOptions, BlockBlobClientCommitBlockListOptions, - BlockBlobClientGetBlockListOptions, BlockBlobClientStageBlockOptions, - BlockBlobClientUploadOptions, -}; +pub use clients::*; pub mod models { pub use crate::generated::models::{ - AccessTier, ArchiveStatus, BlobClientDownloadResult, BlobClientDownloadResultHeaders, + AccessTier, ArchiveStatus, BlobClientDeleteOptions, BlobClientDownloadOptions, + BlobClientDownloadResult, BlobClientDownloadResultHeaders, BlobClientGetPropertiesOptions, BlobClientGetPropertiesResult, BlobClientGetPropertiesResultHeaders, - BlobContainerClientGetPropertiesResult, BlobContainerClientGetPropertiesResultHeaders, - BlobImmutabilityPolicyMode, BlobType, BlockBlobClientCommitBlockListResult, - BlockBlobClientStageBlockResult, BlockBlobClientUploadResult, BlockList, BlockListType, - BlockLookupList, CopyStatus, LeaseState, LeaseStatus, PublicAccessType, RehydratePriority, - StorageServiceProperties, + BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTierOptions, + BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, + BlobContainerClientGetPropertiesOptions, BlobContainerClientGetPropertiesResult, + BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientSetMetadataOptions, + BlobImmutabilityPolicyMode, BlobServiceClientGetPropertiesOptions, BlobType, + BlockBlobClientCommitBlockListOptions, BlockBlobClientCommitBlockListResult, + BlockBlobClientGetBlockListOptions, BlockBlobClientStageBlockOptions, + BlockBlobClientStageBlockResult, BlockBlobClientUploadOptions, BlockBlobClientUploadResult, + BlockList, BlockListType, BlockLookupList, CopyStatus, LeaseState, LeaseStatus, + PublicAccessType, RehydratePriority, StorageServiceProperties, }; } diff --git a/sdk/storage/azure_storage_blob/tests/blob_client.rs b/sdk/storage/azure_storage_blob/tests/blob_client.rs index af31c4a6d0..16a9d3a2de 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_client.rs @@ -6,12 +6,10 @@ use azure_core::{ Bytes, }; use azure_core_test::{recorded, TestContext}; -use azure_storage_blob::{ - models::{ - AccessTier, BlobClientDownloadResultHeaders, BlobClientGetPropertiesResultHeaders, - LeaseState, - }, +use azure_storage_blob::models::{ + AccessTier, BlobClientDownloadResultHeaders, BlobClientGetPropertiesResultHeaders, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlockBlobClientUploadOptions, + LeaseState, }; use azure_storage_blob_test::{create_test_blob, get_blob_name, get_container_client}; use std::{collections::HashMap, error::Error}; diff --git a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs index 81c9e1ebe4..ccd5466754 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs @@ -3,9 +3,9 @@ use azure_core::http::StatusCode; use azure_core_test::{recorded, TestContext}; -use azure_storage_blob::{ - models::{BlobContainerClientGetPropertiesResultHeaders, LeaseState}, - BlobContainerClientSetMetadataOptions, +use azure_storage_blob::models::{ + BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientSetMetadataOptions, + LeaseState, }; use azure_storage_blob_test::get_container_client; use std::{collections::HashMap, error::Error}; diff --git a/sdk/storage/azure_storage_blob/tests/blob_service_client.rs b/sdk/storage/azure_storage_blob/tests/blob_service_client.rs index 957adfb2b4..0077ef903b 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_service_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_service_client.rs @@ -2,7 +2,7 @@ // Licensed under the MIT License. use azure_core_test::{recorded, TestContext}; -use azure_storage_blob::BlobServiceClientGetPropertiesOptions; +use azure_storage_blob::models::BlobServiceClientGetPropertiesOptions; use azure_storage_blob_test::get_blob_service_client; use std::error::Error; diff --git a/sdk/storage/azure_storage_blob/tsp-location.yaml b/sdk/storage/azure_storage_blob/tsp-location.yaml index ce396e3016..2317872844 100644 --- a/sdk/storage/azure_storage_blob/tsp-location.yaml +++ b/sdk/storage/azure_storage_blob/tsp-location.yaml @@ -1,4 +1,4 @@ directory: specification/storage/Microsoft.BlobStorage -commit: a7ede2356175c7825fdb245ec17e5b6df71e1ae3 +commit: 566f9855e2272ffe7d575e560d95f4755b5b0fb5 repo: Azure/azure-rest-api-specs additionalDirectories: diff --git a/sdk/storage/azure_storage_blob_test/src/lib.rs b/sdk/storage/azure_storage_blob_test/src/lib.rs index 7338c7c57b..d8fe702769 100644 --- a/sdk/storage/azure_storage_blob_test/src/lib.rs +++ b/sdk/storage/azure_storage_blob_test/src/lib.rs @@ -27,12 +27,22 @@ fn recorded_test_setup(recording: &Recording) -> (ClientOptions, String) { (client_options, endpoint) } +/// Takes in a Recording instance and returns a randomized blob name with prefix "blob" of length 16. +/// +/// # Arguments +/// +/// * `recording` - A reference to a Recording instance. pub fn get_blob_name(recording: &Recording) -> String { recording .random_string::<12>(Some("blob")) .to_ascii_lowercase() } +/// Takes in a Recording instance and returns a randomized container name with prefix "container" of length 16. +/// +/// # Arguments +/// +/// * `recording` - A reference to a Recording instance. pub fn get_container_name(recording: &Recording) -> String { recording .random_string::<17>(Some("container")) From b19e513b7627024a5b61471fbaf210f955ef274c Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 2 May 2025 14:16:22 -0700 Subject: [PATCH 2/8] ListBlobs, untested --- .../src/clients/blob_container_client.rs | 17 ++++++++- sdk/storage/azure_storage_blob/src/lib.rs | 6 ++- .../tests/blob_container_client.rs | 37 ++++++++++++++++++- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs index e09ff48034..48963a72f7 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs @@ -6,7 +6,8 @@ use crate::{ generated::models::BlobContainerClientGetPropertiesResult, models::{ BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, - BlobContainerClientGetPropertiesOptions, BlobContainerClientSetMetadataOptions, + BlobContainerClientGetPropertiesOptions, BlobContainerClientListBlobFlatSegmentOptions, + BlobContainerClientSetMetadataOptions, ListBlobsFlatSegmentResponse, }, pipeline::StorageHeadersPolicy, BlobClient, BlobContainerClientOptions, @@ -15,7 +16,7 @@ use azure_core::{ credentials::TokenCredential, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - Response, Url, + Pager, Response, Url, }, Result, }; @@ -144,4 +145,16 @@ impl BlobContainerClient { ) -> Result> { self.client.get_properties(options).await } + + /// Returns a list of the blobs under the specified container. + /// + /// # Arguments + /// + /// * `options` - Optional configuration for the request. + pub async fn list_blobs( + &self, + options: Option>, + ) -> Result> { + self.client.list_blob_flat_segment(options) + } } diff --git a/sdk/storage/azure_storage_blob/src/lib.rs b/sdk/storage/azure_storage_blob/src/lib.rs index b0e83f0e00..0e8fa822ae 100644 --- a/sdk/storage/azure_storage_blob/src/lib.rs +++ b/sdk/storage/azure_storage_blob/src/lib.rs @@ -21,12 +21,14 @@ pub mod models { BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTierOptions, BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, BlobContainerClientGetPropertiesOptions, BlobContainerClientGetPropertiesResult, - BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientSetMetadataOptions, + BlobContainerClientGetPropertiesResultHeaders, + BlobContainerClientListBlobFlatSegmentOptions, BlobContainerClientSetMetadataOptions, BlobImmutabilityPolicyMode, BlobServiceClientGetPropertiesOptions, BlobType, BlockBlobClientCommitBlockListOptions, BlockBlobClientCommitBlockListResult, BlockBlobClientGetBlockListOptions, BlockBlobClientStageBlockOptions, BlockBlobClientStageBlockResult, BlockBlobClientUploadOptions, BlockBlobClientUploadResult, BlockList, BlockListType, BlockLookupList, CopyStatus, LeaseState, LeaseStatus, - PublicAccessType, RehydratePriority, StorageServiceProperties, + ListBlobsFlatSegmentResponse, PublicAccessType, RehydratePriority, + StorageServiceProperties, }; } diff --git a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs index ccd5466754..0f1b8af0a4 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -use azure_core::http::StatusCode; +use azure_core::http::{Page, Pager, PagerResult, RequestContent, StatusCode}; use azure_core_test::{recorded, TestContext}; use azure_storage_blob::models::{ BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientSetMetadataOptions, - LeaseState, + LeaseState, ListBlobsFlatSegmentResponse, }; use azure_storage_blob_test::get_container_client; use std::{collections::HashMap, error::Error}; @@ -82,3 +82,36 @@ async fn test_set_container_metadata(ctx: TestContext) -> Result<(), Box Result<(), Box> { + // Recording Setup + let recording = ctx.recording(); + let container_client = get_container_client(recording, false).await?; + let blob_client_1 = container_client.blob_client("testblob1".to_string()); + let blob_client_2 = container_client.blob_client("testblob2".to_string()); + + container_client.create_container(None).await?; + let data = b"hello rusty world"; + blob_client_1 + .upload( + RequestContent::from(data.to_vec()), + false, + u64::try_from(data.len())?, + None, + ) + .await?; + blob_client_2 + .upload( + RequestContent::from(data.to_vec()), + false, + u64::try_from(data.len())?, + None, + ) + .await?; + + let blob_list = container_client.list_blobs(None).await?; + + container_client.delete_container(None).await?; + Ok(()) +} From cc2058d77260b3994e595ecfd9c93d9c0f20db3d Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 2 May 2025 15:07:21 -0700 Subject: [PATCH 3/8] list_blobs first test attempt, infinite loop and empty page response --- Cargo.lock | 1 + sdk/storage/azure_storage_blob/Cargo.toml | 1 + .../tests/blob_container_client.rs | 64 ++++++++++++++++++- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53f9acd0a1..9c2aa4c284 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -400,6 +400,7 @@ dependencies = [ "azure_core_test", "azure_identity", "azure_storage_blob_test", + "futures", "serde", "time", "tokio", diff --git a/sdk/storage/azure_storage_blob/Cargo.toml b/sdk/storage/azure_storage_blob/Cargo.toml index 9cc1244e34..0280f26bc5 100644 --- a/sdk/storage/azure_storage_blob/Cargo.toml +++ b/sdk/storage/azure_storage_blob/Cargo.toml @@ -18,6 +18,7 @@ categories = ["api-bindings"] [dependencies] async-trait.workspace = true azure_core = { workspace = true, features = ["xml"] } +futures.workspace = true serde.workspace = true time.workspace = true typespec_client_core = { workspace = true, features = ["derive"] } diff --git a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs index 0f1b8af0a4..3057d1c6c7 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -use azure_core::http::{Page, Pager, PagerResult, RequestContent, StatusCode}; +use azure_core::http::{Pager, PagerResult, RequestContent, StatusCode}; use azure_core_test::{recorded, TestContext}; use azure_storage_blob::models::{ BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientSetMetadataOptions, LeaseState, ListBlobsFlatSegmentResponse, }; use azure_storage_blob_test::get_container_client; +use futures::TryStreamExt; use std::{collections::HashMap, error::Error}; #[recorded::test] @@ -110,7 +111,66 @@ async fn test_list_blobs(ctx: TestContext) -> Result<(), Box> { ) .await?; - let blob_list = container_client.list_blobs(None).await?; + let mut list_blobs_response = container_client.list_blobs(None).await?; + + while let Some(page) = list_blobs_response.try_next().await? { + let list_blob_segment_response = page.into_body().await?; + let blob_list = list_blob_segment_response.segment.blob_items; + for blob in blob_list { + println!("{}", blob.name.unwrap().content.unwrap()) + } + } + + container_client.delete_container(None).await?; + Ok(()) +} + +#[recorded::test] +async fn test_list_blobs_2(ctx: TestContext) -> Result<(), Box> { + // Recording Setup + let recording = ctx.recording(); + let container_client = get_container_client(recording, false).await?; + let blob_client_1 = container_client.blob_client("testblob1".to_string()); + let blob_client_2 = container_client.blob_client("testblob2".to_string()); + + container_client.create_container(None).await?; + let data = b"hello rusty world"; + blob_client_1 + .upload( + RequestContent::from(data.to_vec()), + false, + u64::try_from(data.len())?, + None, + ) + .await?; + blob_client_2 + .upload( + RequestContent::from(data.to_vec()), + false, + u64::try_from(data.len())?, + None, + ) + .await?; + + let mut list_blobs_response = container_client.list_blobs(None).await?; + let mut count = 0; + + while let Some(page) = list_blobs_response.try_next().await? { + println!("while: {}", count); + count += 1; + let list_blob_segment_response = page.into_body().await?; + let blob_list = list_blob_segment_response.segment.blob_items; + + // for blob in blob_list { + // println!("inside of inner for-loop"); + // println!("{}", blob.name.unwrap().content.unwrap()) + // } + + let first_slice = blob_list.first(); + println!("Is this some? {}", first_slice.is_some()); + + println!("bottom of outer while-loop reached") + } container_client.delete_container(None).await?; Ok(()) From 306e8068aa262fba35dbf3bae84bf6b040e52e1a Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Tue, 27 May 2025 12:28:59 -0700 Subject: [PATCH 4/8] Sync emitter-package.json to v14.1 --- eng/emitter-package.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/eng/emitter-package.json b/eng/emitter-package.json index 817fd5be76..25892cbbe0 100644 --- a/eng/emitter-package.json +++ b/eng/emitter-package.json @@ -1,17 +1,17 @@ { "main": "dist/src/index.js", "dependencies": { - "@azure-tools/typespec-rust": "0.14.0" + "@azure-tools/typespec-rust": "0.14.1" }, "devDependencies": { - "@azure-tools/typespec-azure-core": "0.55.0", - "@azure-tools/typespec-azure-rulesets": "0.55.0", - "@azure-tools/typespec-client-generator-core": "0.55.1", - "@typespec/compiler": "1.0.0-rc.1", - "@typespec/http": "1.0.0-rc.1", - "@typespec/openapi": "1.0.0-rc.1", - "@typespec/rest": "0.69.0", - "@typespec/versioning": "0.69.0", - "@typespec/xml": "0.69.0" + "@azure-tools/typespec-azure-core": "0.56.0", + "@azure-tools/typespec-azure-rulesets": "0.56.0", + "@azure-tools/typespec-client-generator-core": "0.56.1", + "@typespec/compiler": "1.0.0", + "@typespec/http": "1.0.0", + "@typespec/openapi": "1.0.0", + "@typespec/rest": "0.70.0", + "@typespec/versioning": "0.70.0", + "@typespec/xml": "0.70.0" } -} +} \ No newline at end of file From 0818001c09ad6e733b66adbf8339d65cc3886e8b Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Wed, 28 May 2025 16:13:42 -0700 Subject: [PATCH 5/8] Regen against v14.2, list_blobs done but odd maxresults results --- eng/emitter-package-lock.json | 366 +++++++++--------- eng/emitter-package.json | 6 +- sdk/storage/.dict.txt | 4 + sdk/storage/assets.json | 2 +- .../generated/clients/append_blob_client.rs | 2 +- .../src/generated/clients/blob_client.rs | 2 +- .../clients/blob_container_client.rs | 20 +- .../generated/clients/blob_service_client.rs | 10 +- .../generated/clients/block_blob_client.rs | 2 +- .../src/generated/clients/page_blob_client.rs | 6 +- .../src/generated/models/pub_models.rs | 34 +- .../src/generated/models/xml_helpers.rs | 55 +-- .../tests/blob_container_client.rs | 130 +++---- .../azure_storage_blob/tsp-location.yaml | 2 +- 14 files changed, 289 insertions(+), 352 deletions(-) diff --git a/eng/emitter-package-lock.json b/eng/emitter-package-lock.json index 4982498aba..7e46633a76 100644 --- a/eng/emitter-package-lock.json +++ b/eng/emitter-package-lock.json @@ -5,18 +5,18 @@ "packages": { "": { "dependencies": { - "@azure-tools/typespec-rust": "0.14.0" + "@azure-tools/typespec-rust": "0.14.2" }, "devDependencies": { - "@azure-tools/typespec-azure-core": "0.55.0", - "@azure-tools/typespec-azure-rulesets": "0.55.0", - "@azure-tools/typespec-client-generator-core": "0.55.1", - "@typespec/compiler": "1.0.0-rc.1", - "@typespec/http": "1.0.0-rc.1", - "@typespec/openapi": "1.0.0-rc.1", - "@typespec/rest": "0.69.0", - "@typespec/versioning": "0.69.0", - "@typespec/xml": "0.69.0" + "@azure-tools/typespec-azure-core": "0.56.0", + "@azure-tools/typespec-azure-rulesets": "0.56.0", + "@azure-tools/typespec-client-generator-core": "0.56.2", + "@typespec/compiler": "1.0.0", + "@typespec/http": "1.0.1", + "@typespec/openapi": "1.0.0", + "@typespec/rest": "0.70.0", + "@typespec/versioning": "0.70.0", + "@typespec/xml": "0.70.0" } }, "node_modules/@azure-tools/async-io": { @@ -33,14 +33,14 @@ } }, "node_modules/@azure-tools/codegen": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@azure-tools/codegen/-/codegen-2.10.0.tgz", - "integrity": "sha512-gdy0at3BUZAAARgiX9Ye6SNCKhcjLs5FNUewa/KV/dMGcPv7mBvbslt5VO3W8wj0n96ifk970aIFaivjacBxeQ==", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@azure-tools/codegen/-/codegen-2.10.1.tgz", + "integrity": "sha512-fZfREKjQnBTscjObgK4LuyZNFaofoCNQDNz0jl1i8fYNwCM5EOF9BXwtEtobuEyCpPUNDxQ/KKO65eWzirqk4w==", "license": "MIT", "dependencies": { "@azure-tools/async-io": "~3.0.0", "js-yaml": "~4.1.0", - "semver": "^7.3.5" + "semver": "^7.7.2" }, "engines": { "node": ">=12.0.0" @@ -65,23 +65,23 @@ } }, "node_modules/@azure-tools/typespec-azure-core": { - "version": "0.55.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.55.0.tgz", - "integrity": "sha512-gDHTm9UYDIbSoBOVsi4Sf+Ly40gnEpIWzqe3KS1H75YB1XXF8ciSnFen3G2bw8EQIj5pcbvP6ZEv18Sy4SJEDg==", + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.56.0.tgz", + "integrity": "sha512-5Pb2p9MQJqcyQyptM/oo98ws3IXkXl14hVaaORFi+4VTRsOtALvnHdrUvnUQ9iTJrHioaXPxhR2+W7VuotoXsQ==", "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1", - "@typespec/http": "^1.0.0-rc.1", - "@typespec/rest": "^0.69.0" + "@typespec/compiler": "^1.0.0", + "@typespec/http": "^1.0.0", + "@typespec/rest": "^0.70.0" } }, "node_modules/@azure-tools/typespec-azure-resource-manager": { - "version": "0.55.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-resource-manager/-/typespec-azure-resource-manager-0.55.0.tgz", - "integrity": "sha512-7ff1q3ddamt7DYl00YdrFC3qMLNfI2ihH22nQr96BbOpxl4Pa7pvJFcv4cdi6PExjakKfuCXAKr/x0ukxnxCpQ==", + "version": "0.56.1", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-resource-manager/-/typespec-azure-resource-manager-0.56.1.tgz", + "integrity": "sha512-5xboTqN4V1G3O9zVthtgJ3VJ6P9+6g7Hz+tYVQHDwTQfirwYRt01DTmqg/JNrCUC3KLsufSbz1T++jApUTNGGA==", "dev": true, "license": "MIT", "peer": true, @@ -93,34 +93,34 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.55.0", - "@typespec/compiler": "^1.0.0-rc.1", - "@typespec/http": "^1.0.0-rc.1", - "@typespec/openapi": "^1.0.0-rc.1", - "@typespec/rest": "^0.69.0", - "@typespec/versioning": "^0.69.0" + "@azure-tools/typespec-azure-core": "^0.56.0", + "@typespec/compiler": "^1.0.0", + "@typespec/http": "^1.0.1", + "@typespec/openapi": "^1.0.0", + "@typespec/rest": "^0.70.0", + "@typespec/versioning": "^0.70.0" } }, "node_modules/@azure-tools/typespec-azure-rulesets": { - "version": "0.55.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-rulesets/-/typespec-azure-rulesets-0.55.0.tgz", - "integrity": "sha512-RquIvTz2dEkew6Wfj6mYld79k5co/NWrQGR3qdAwcLtp8RVOzDFk6QwKPn9f71UnQkzwuV8Z3bOtXmR/c8MDrg==", + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-rulesets/-/typespec-azure-rulesets-0.56.0.tgz", + "integrity": "sha512-V073uLUTGBYhn5MyOS2RHUadYuYGYrFDlhuvqoAUNDG/v8CSWEyXx4CHo8dq+Y/0DauLc9YfNzwXrDgtlW9HrA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.55.0", - "@azure-tools/typespec-azure-resource-manager": "^0.55.0", - "@azure-tools/typespec-client-generator-core": "^0.55.0", - "@typespec/compiler": "^1.0.0-rc.1" + "@azure-tools/typespec-azure-core": "^0.56.0", + "@azure-tools/typespec-azure-resource-manager": "^0.56.0", + "@azure-tools/typespec-client-generator-core": "^0.56.0", + "@typespec/compiler": "^1.0.0" } }, "node_modules/@azure-tools/typespec-client-generator-core": { - "version": "0.55.1", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.55.1.tgz", - "integrity": "sha512-VmjOHWk2bBoFFB2/pLsGR1LZudLff4kEUEhSJX8jQQ23Y5BiT8f2PknB6DUohTpYnWcKIVZDXle+ObjqspS1Pw==", + "version": "0.56.2", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.56.2.tgz", + "integrity": "sha512-KplQWeC/iyUTaPfBAdKynCRon8BH15yc34NBXWsjllRz+X+ZwxCQeU3vxzHQnrUPTXtNKhjXpu/les1fdd/rDQ==", "license": "MIT", "dependencies": { "change-case": "~5.4.4", @@ -131,29 +131,29 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.55.0", - "@typespec/compiler": "^1.0.0-rc.1", - "@typespec/events": "^0.69.0", - "@typespec/http": "^1.0.0-rc.1", - "@typespec/openapi": "^1.0.0-rc.1", - "@typespec/rest": "^0.69.0", - "@typespec/sse": "^0.69.0", - "@typespec/streams": "^0.69.0", - "@typespec/versioning": "^0.69.0", - "@typespec/xml": "^0.69.0" + "@azure-tools/typespec-azure-core": "^0.56.0", + "@typespec/compiler": "^1.0.0", + "@typespec/events": "^0.70.0", + "@typespec/http": "^1.0.1", + "@typespec/openapi": "^1.0.0", + "@typespec/rest": "^0.70.0", + "@typespec/sse": "^0.70.0", + "@typespec/streams": "^0.70.0", + "@typespec/versioning": "^0.70.0", + "@typespec/xml": "^0.70.0" } }, "node_modules/@azure-tools/typespec-rust": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-rust/-/typespec-rust-0.14.0.tgz", - "integrity": "sha512-2X11ZCTUKeDNiCJQ4vLOk10C/sZWlXFCVU36IciT9yAMNGPxtQumBpgWUpSkasA+qUDVwfDuRDV7cHNDlXcyCQ==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-rust/-/typespec-rust-0.14.2.tgz", + "integrity": "sha512-jTydFlu0hu2Muhv6YmFMKwwq86HfWS+qACIyGkA/wGsE83UHD7P6DP/lNRfqPwpKerK/5TTyBXsX1ytwcVVVAg==", "license": "MIT", "dependencies": { "@azure-tools/codegen": "~2.10.0", "@azure-tools/linq": "~3.1.263", "@types/turndown": "^5.0.5", "linkifyjs": "^4.2.0", - "query-string": "9.1.1", + "query-string": "9.2.0", "source-map-support": "0.5.21", "turndown": "^7.2.0" }, @@ -161,9 +161,9 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-client-generator-core": ">=0.55.1 <1.0.0", - "@typespec/compiler": ">=1.0.0-rc.1 <1.0.0", - "@typespec/http": ">=1.0.0-rc.1 <1.0.0" + "@azure-tools/typespec-client-generator-core": ">=0.56.2 <1.0.0", + "@typespec/compiler": "^1.0.0", + "@typespec/http": "^1.0.1" } }, "node_modules/@babel/code-frame": { @@ -190,14 +190,14 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.5.tgz", - "integrity": "sha512-swPczVU+at65xa5uPfNP9u3qx/alNwiaykiI/ExpsmMSQW55trmZcwhYWzw/7fj+n6Q8z1eENvR7vFfq9oPSAQ==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.8.tgz", + "integrity": "sha512-d/QAsnwuHX2OPolxvYcgSj7A9DO9H6gVOy2DvBTx+P2LH2iRTo/RSGV3iwCzW024nP9hw98KIuDmdyhZQj1UQg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.6", + "@inquirer/core": "^10.1.13", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -214,13 +214,13 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.9.tgz", - "integrity": "sha512-NgQCnHqFTjF7Ys2fsqK2WtnA8X1kHyInyG+nMIuHowVTIgIuS10T4AznI/PvbqSpJqjCUqNBlKGh1v3bwLFL4w==", + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.12.tgz", + "integrity": "sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/type": "^3.0.6" + "@inquirer/core": "^10.1.13", + "@inquirer/type": "^3.0.7" }, "engines": { "node": ">=18" @@ -235,13 +235,13 @@ } }, "node_modules/@inquirer/core": { - "version": "10.1.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.10.tgz", - "integrity": "sha512-roDaKeY1PYY0aCqhRmXihrHjoSW2A00pV3Ke5fTpMCkzcGF64R8e0lw3dK+eLEHwS4vB5RnW1wuQmvzoRul8Mw==", + "version": "10.1.13", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.13.tgz", + "integrity": "sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==", "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.6", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", @@ -262,13 +262,13 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.10.tgz", - "integrity": "sha512-5GVWJ+qeI6BzR6TIInLP9SXhWCEcvgFQYmcRG6d6RIlhFjM5TyG18paTGBgRYyEouvCmzeco47x9zX9tQEofkw==", + "version": "4.2.13", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.13.tgz", + "integrity": "sha512-WbicD9SUQt/K8O5Vyk9iC2ojq5RHoCLK6itpp2fHsWe44VxxcA9z3GTWlvjSTGmMQpZr+lbVmrxdHcumJoLbMA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/type": "^3.0.6", + "@inquirer/core": "^10.1.13", + "@inquirer/type": "^3.0.7", "external-editor": "^3.1.0" }, "engines": { @@ -284,13 +284,13 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.12.tgz", - "integrity": "sha512-jV8QoZE1fC0vPe6TnsOfig+qwu7Iza1pkXoUJ3SroRagrt2hxiL+RbM432YAihNR7m7XnU0HWl/WQ35RIGmXHw==", + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.15.tgz", + "integrity": "sha512-4Y+pbr/U9Qcvf+N/goHzPEXiHH8680lM3Dr3Y9h9FFw4gHS+zVpbj8LfbKWIb/jayIB4aSO4pWiBTrBYWkvi5A==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/type": "^3.0.6", + "@inquirer/core": "^10.1.13", + "@inquirer/type": "^3.0.7", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -306,22 +306,22 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.11.tgz", - "integrity": "sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw==", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", + "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@inquirer/input": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.9.tgz", - "integrity": "sha512-mshNG24Ij5KqsQtOZMgj5TwEjIf+F2HOESk6bjMwGWgcH5UBe8UoljwzNFHqdMbGYbgAf6v2wU/X9CAdKJzgOA==", + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.12.tgz", + "integrity": "sha512-xJ6PFZpDjC+tC1P8ImGprgcsrzQRsUh9aH3IZixm1lAZFK49UGHxM3ltFfuInN2kPYNfyoPRh+tU4ftsjPLKqQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/type": "^3.0.6" + "@inquirer/core": "^10.1.13", + "@inquirer/type": "^3.0.7" }, "engines": { "node": ">=18" @@ -336,13 +336,13 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.12.tgz", - "integrity": "sha512-7HRFHxbPCA4e4jMxTQglHJwP+v/kpFsCf2szzfBHy98Wlc3L08HL76UDiA87TOdX5fwj2HMOLWqRWv9Pnn+Z5Q==", + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.15.tgz", + "integrity": "sha512-xWg+iYfqdhRiM55MvqiTCleHzszpoigUpN5+t1OMcRkJrUrw7va3AzXaxvS+Ak7Gny0j2mFSTv2JJj8sMtbV2g==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/type": "^3.0.6" + "@inquirer/core": "^10.1.13", + "@inquirer/type": "^3.0.7" }, "engines": { "node": ">=18" @@ -357,13 +357,13 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.12.tgz", - "integrity": "sha512-FlOB0zvuELPEbnBYiPaOdJIaDzb2PmJ7ghi/SVwIHDDSQ2K4opGBkF+5kXOg6ucrtSUQdLhVVY5tycH0j0l+0g==", + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.15.tgz", + "integrity": "sha512-75CT2p43DGEnfGTaqFpbDC2p2EEMrq0S+IRrf9iJvYreMy5mAWj087+mdKyLHapUEPLjN10mNvABpGbk8Wdraw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/type": "^3.0.6", + "@inquirer/core": "^10.1.13", + "@inquirer/type": "^3.0.7", "ansi-escapes": "^4.3.2" }, "engines": { @@ -379,21 +379,21 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.5.0.tgz", - "integrity": "sha512-tk8Bx7l5AX/CR0sVfGj3Xg6v7cYlFBkEahH+EgBB+cZib6Fc83dwerTbzj7f2+qKckjIUGsviWRI1d7lx6nqQA==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.5.3.tgz", + "integrity": "sha512-8YL0WiV7J86hVAxrh3fE5mDCzcTDe1670unmJRz6ArDgN+DBK1a0+rbnNWp4DUB5rPMwqD5ZP6YHl9KK1mbZRg==", "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.1.5", - "@inquirer/confirm": "^5.1.9", - "@inquirer/editor": "^4.2.10", - "@inquirer/expand": "^4.0.12", - "@inquirer/input": "^4.1.9", - "@inquirer/number": "^3.0.12", - "@inquirer/password": "^4.0.12", - "@inquirer/rawlist": "^4.1.0", - "@inquirer/search": "^3.0.12", - "@inquirer/select": "^4.2.0" + "@inquirer/checkbox": "^4.1.8", + "@inquirer/confirm": "^5.1.12", + "@inquirer/editor": "^4.2.13", + "@inquirer/expand": "^4.0.15", + "@inquirer/input": "^4.1.12", + "@inquirer/number": "^3.0.15", + "@inquirer/password": "^4.0.15", + "@inquirer/rawlist": "^4.1.3", + "@inquirer/search": "^3.0.15", + "@inquirer/select": "^4.2.3" }, "engines": { "node": ">=18" @@ -408,13 +408,13 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.0.tgz", - "integrity": "sha512-6ob45Oh9pXmfprKqUiEeMz/tjtVTFQTgDDz1xAMKMrIvyrYjAmRbQZjMJfsictlL4phgjLhdLu27IkHNnNjB7g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.3.tgz", + "integrity": "sha512-7XrV//6kwYumNDSsvJIPeAqa8+p7GJh7H5kRuxirct2cgOcSWwwNGoXDRgpNFbY/MG2vQ4ccIWCi8+IXXyFMZA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/type": "^3.0.6", + "@inquirer/core": "^10.1.13", + "@inquirer/type": "^3.0.7", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -430,14 +430,14 @@ } }, "node_modules/@inquirer/search": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.12.tgz", - "integrity": "sha512-H/kDJA3kNlnNIjB8YsaXoQI0Qccgf0Na14K1h8ExWhNmUg2E941dyFPrZeugihEa9AZNW5NdsD/NcvUME83OPQ==", + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.15.tgz", + "integrity": "sha512-YBMwPxYBrADqyvP4nNItpwkBnGGglAvCLVW8u4pRmmvOsHUtCAUIMbUrLX5B3tFL1/WsLGdQ2HNzkqswMs5Uaw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.6", + "@inquirer/core": "^10.1.13", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -453,14 +453,14 @@ } }, "node_modules/@inquirer/select": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.2.0.tgz", - "integrity": "sha512-KkXQ4aSySWimpV4V/TUJWdB3tdfENZUU765GjOIZ0uPwdbGIG6jrxD4dDf1w68uP+DVtfNhr1A92B+0mbTZ8FA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.2.3.tgz", + "integrity": "sha512-OAGhXU0Cvh0PhLz9xTF/kx6g6x+sP+PcyTiLvCrewI99P3BBeexD+VbuwkNDvqGkk3y2h5ZiWLeRP7BFlhkUDg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.10", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.6", + "@inquirer/core": "^10.1.13", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -477,9 +477,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.6.tgz", - "integrity": "sha512-/mKVCtVpyBu3IDarv0G+59KC4stsD5mDsGpYh+GKs1NZT88Jh52+cuoA1AtLk2Q0r/quNl+1cSUyLRHBFeD0XA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.7.tgz", + "integrity": "sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==", "license": "MIT", "engines": { "node": ">=18" @@ -565,9 +565,9 @@ "license": "MIT" }, "node_modules/@typespec/compiler": { - "version": "1.0.0-rc.1", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.0.0-rc.1.tgz", - "integrity": "sha512-SDCB19wCVQVGTHOwkKnOnaGH2/vpr5aHLhTOs2k36AVsFrkurpMkL0TeE2QKiJszmkQeOnGW3bgH7Hbw15kXtw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.0.0.tgz", + "integrity": "sha512-QFy0otaB4xkN4kQmYyT17yu3OVhN0gti9+EKnZqs5JFylw2Xecx22BPwUE1Byj42pZYg5d9WlO+WwmY5ALtRDg==", "license": "MIT", "dependencies": { "@babel/code-frame": "~7.26.2", @@ -597,29 +597,29 @@ } }, "node_modules/@typespec/events": { - "version": "0.69.0", - "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.69.0.tgz", - "integrity": "sha512-2uq9s9yvqcTAvpIPdXBJ2QHMhQ5WhL5RwpbvvoHHx0locY7Ny9nmXCxFPF3MysHE9g4KK2CVwVB9RCu4i4q8Lw==", + "version": "0.70.0", + "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.70.0.tgz", + "integrity": "sha512-qHW1N05n8PkNf2YQGNMdl/sAYqrJv+zQ1kny+3vg/20nzVj7sZpNFIKqUIc11z0GkT7k3Q9SPTymvq+K00sAUg==", "license": "MIT", "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1" + "@typespec/compiler": "^1.0.0" } }, "node_modules/@typespec/http": { - "version": "1.0.0-rc.1", - "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.0.0-rc.1.tgz", - "integrity": "sha512-USAxsTeRF1i4g39KeHOh7/x1RzW4lpSpWQqlz/xuHAxEPVsu23BRq9AJrN/nTpgYlpGvOTbJnadWXOs20/TmBA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.0.1.tgz", + "integrity": "sha512-J5tqBWlmkvI/W+kJn4EFuN0laGxbY8qT68jzEQEiYeAXSfNyFGRSoCwn8Ex6dJphq4IozOMdVTNtOZWIJlwmfw==", "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1", - "@typespec/streams": "^0.69.0" + "@typespec/compiler": "^1.0.0", + "@typespec/streams": "^0.70.0" }, "peerDependenciesMeta": { "@typespec/streams": { @@ -628,82 +628,82 @@ } }, "node_modules/@typespec/openapi": { - "version": "1.0.0-rc.1", - "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.0.0-rc.1.tgz", - "integrity": "sha512-lHfn6luTc4OKpspHFfxnUD65+jhFvtp2YavCCagVZotl14U8+mxAXULZDwRgi2Wu5/CdII0v5WnA+yu1DSbFzA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.0.0.tgz", + "integrity": "sha512-pONzKIdK4wHgD1vBfD9opUk66zDG55DlHbueKOldH2p1LVf5FnMiuKE4kW0pl1dokT/HBNR5OJciCzzVf44AgQ==", "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1", - "@typespec/http": "^1.0.0-rc.1" + "@typespec/compiler": "^1.0.0", + "@typespec/http": "^1.0.0" } }, "node_modules/@typespec/rest": { - "version": "0.69.0", - "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.69.0.tgz", - "integrity": "sha512-rbYG0XG6UYapJ6yG9Ytk5djkuaJ3QHG0WEQ01KpdNl4XEfpelH7wLStShP85nxrP4hmNZ6Slqm1Zng2kcyjkww==", + "version": "0.70.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.70.0.tgz", + "integrity": "sha512-pn3roMQV6jBNT4bVA/hnrBAAHleXSyfWQqNO+DhI3+tLU4jCrJHmUZDi82nI9xBl+jkmy2WZFZOelZA9PSABeg==", "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1", - "@typespec/http": "^1.0.0-rc.1" + "@typespec/compiler": "^1.0.0", + "@typespec/http": "^1.0.0" } }, "node_modules/@typespec/sse": { - "version": "0.69.0", - "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.69.0.tgz", - "integrity": "sha512-IEuiW6Su+HzDPYAJqACgKisRZPxQ1SvLynBuNfm1nLD/VXhINzQboMbnoGeBxa6lZZlSzoyVlP5WG+4XBZnkVg==", + "version": "0.70.0", + "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.70.0.tgz", + "integrity": "sha512-11VsIRqPuK+bIq7gHVghM5CAqvcfe9TmL9mZkxlPKuV6RRWju831k18KqlwXTOgeEMwVGA1Xbg1TTi1F4S1B+w==", "license": "MIT", "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1", - "@typespec/events": "^0.69.0", - "@typespec/http": "^1.0.0-rc.1", - "@typespec/streams": "^0.69.0" + "@typespec/compiler": "^1.0.0", + "@typespec/events": "^0.70.0", + "@typespec/http": "^1.0.0", + "@typespec/streams": "^0.70.0" } }, "node_modules/@typespec/streams": { - "version": "0.69.0", - "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.69.0.tgz", - "integrity": "sha512-4GIXjWYUI38MEbq1hWfBEwvrze18sAsgWn7OQKFSTg+SvE6VDVP1J6Hfr4Ps+wNmn3x9tySEyX1NrwBlAZSJDQ==", + "version": "0.70.0", + "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.70.0.tgz", + "integrity": "sha512-WIixoZ7CCLq2INX4UkN+aXlj07Je+ntW0xbeFGmpfq6Z2xifKnL6/sPiztURMXd4Z1I+XXFCn2pw1r9q5i4Cmw==", "license": "MIT", "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1" + "@typespec/compiler": "^1.0.0" } }, "node_modules/@typespec/versioning": { - "version": "0.69.0", - "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.69.0.tgz", - "integrity": "sha512-RqSd4Ee2O/6LdcQg2YfLgbsB6up0N8MGKFIxQ8PwE3z3l4lJju3chBMyBZxTxhaV293j7oUZr6+2CvfqwX2IWw==", + "version": "0.70.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.70.0.tgz", + "integrity": "sha512-LvuhDGJU9ksdUKuBZLBle7n9/xlS4e18kg5cqPpQGUI0hx9KSrZtXMoL6VRpoBVtEWcAmn4Q5dBL3+K4ur7/vg==", "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1" + "@typespec/compiler": "^1.0.0" } }, "node_modules/@typespec/xml": { - "version": "0.69.0", - "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.69.0.tgz", - "integrity": "sha512-GomNfjvDIQXQv324ThQGteo8lKzecOitrJ1a1R72RvvUIKS2h5KPiGKwj/AQNT5c7r4EaqQXhd2OzZRrwg1SEA==", + "version": "0.70.0", + "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.70.0.tgz", + "integrity": "sha512-8feX+sFx2OVlGOZ3Bl9G/VFwbqbz6reVt8yllfO4aY0EVSM3GxIB7TivZofBrxDRYvwEADpc8+2gI+kdJaSL1w==", "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.0.0-rc.1" + "@typespec/compiler": "^1.0.0" } }, "node_modules/ajv": { @@ -1129,9 +1129,9 @@ "license": "MIT" }, "node_modules/linkifyjs": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.2.0.tgz", - "integrity": "sha512-pCj3PrQyATaoTYKHrgWRF3SJwsm61udVh+vuls/Rl6SptiDhgE7ziUIudAedRY9QEfynmM7/RmLEfPUyw1HPCw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.1.tgz", + "integrity": "sha512-DRSlB9DKVW04c4SUdGvKK5FR6be45lTU9M76JnngqPeeGDqPwYc0zdUErtsNVMtxPXgUWV4HbXbnC4sNyBxkYg==", "license": "MIT" }, "node_modules/merge2": { @@ -1287,9 +1287,9 @@ } }, "node_modules/query-string": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-9.1.1.tgz", - "integrity": "sha512-MWkCOVIcJP9QSKU52Ngow6bsAWAPlPK2MludXvcrS2bGZSl+T1qX9MZvRIkqUIkGLJquMJHWfsT6eRqUpp4aWg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-9.2.0.tgz", + "integrity": "sha512-YIRhrHujoQxhexwRLxfy3VSjOXmvZRd2nyw1PwL1UUqZ/ys1dEZd1+NSgXkne2l/4X/7OXkigEAuhTX0g/ivJQ==", "license": "MIT", "dependencies": { "decode-uri-component": "^0.4.1", @@ -1390,9 +1390,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "license": "ISC", "bin": { "semver": "bin/semver.js" diff --git a/eng/emitter-package.json b/eng/emitter-package.json index 25892cbbe0..02c4bb766b 100644 --- a/eng/emitter-package.json +++ b/eng/emitter-package.json @@ -1,14 +1,14 @@ { "main": "dist/src/index.js", "dependencies": { - "@azure-tools/typespec-rust": "0.14.1" + "@azure-tools/typespec-rust": "0.14.2" }, "devDependencies": { "@azure-tools/typespec-azure-core": "0.56.0", "@azure-tools/typespec-azure-rulesets": "0.56.0", - "@azure-tools/typespec-client-generator-core": "0.56.1", + "@azure-tools/typespec-client-generator-core": "0.56.2", "@typespec/compiler": "1.0.0", - "@typespec/http": "1.0.0", + "@typespec/http": "1.0.1", "@typespec/openapi": "1.0.0", "@typespec/rest": "0.70.0", "@typespec/versioning": "0.70.0", diff --git a/sdk/storage/.dict.txt b/sdk/storage/.dict.txt index bc9d56ec12..1c4831b113 100644 --- a/sdk/storage/.dict.txt +++ b/sdk/storage/.dict.txt @@ -20,3 +20,7 @@ uncommittedblobs policyid ruleid westus +testblob1 +testblob2 +testblob3 +testblob4 diff --git a/sdk/storage/assets.json b/sdk/storage/assets.json index e28deb2393..0414da4f2c 100644 --- a/sdk/storage/assets.json +++ b/sdk/storage/assets.json @@ -1,6 +1,6 @@ { "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "rust", - "Tag": "rust/azure_storage_blob_be0a70462b", + "Tag": "rust/azure_storage_blob_cdaf5c2731", "TagPrefix": "rust/azure_storage_blob" } \ No newline at end of file diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs index b9dc3e7e94..a9bfe32a7e 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs @@ -334,7 +334,7 @@ impl AppendBlobClient { let mut request = Request::new(url, Method::Put); request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); - request.insert_header("content-type", "application/octet-stream"); + request.insert_header("content-type", "application/xml"); if let Some(if_match) = options.if_match { request.insert_header("if-match", if_match); } diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs index 02e3d89730..974e609213 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs @@ -801,7 +801,7 @@ impl BlobClient { } let mut request = Request::new(url, Method::Head); request.insert_header("accept", "application/json"); - request.insert_header("content-type", "application/octet-stream"); + request.insert_header("content-type", ""); if let Some(if_match) = options.if_match { request.insert_header("if-match", if_match); } diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs index efa44f3924..36895fc8b0 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs @@ -561,12 +561,14 @@ impl BlobContainerClient { let bytes = body.collect().await?; let res: ListBlobsFlatSegmentResponse = xml::read_xml(&bytes)?; let rsp = Response::from_bytes(status, headers, bytes); - Ok(match res.next_marker { - Some(next_marker) => PagerResult::Continue { + let next_marker = res.next_marker.unwrap_or_default(); + Ok(if next_marker.is_empty() { + PagerResult::Complete { response: rsp } + } else { + PagerResult::Continue { response: rsp, continuation: next_marker, - }, - None => PagerResult::Complete { response: rsp }, + } }) } })) @@ -654,12 +656,14 @@ impl BlobContainerClient { let bytes = body.collect().await?; let res: ListBlobsHierarchySegmentResponse = xml::read_xml(&bytes)?; let rsp = Response::from_bytes(status, headers, bytes); - Ok(match res.next_marker { - Some(next_marker) => PagerResult::Continue { + let next_marker = res.next_marker.unwrap_or_default(); + Ok(if next_marker.is_empty() { + PagerResult::Complete { response: rsp } + } else { + PagerResult::Continue { response: rsp, continuation: next_marker, - }, - None => PagerResult::Complete { response: rsp }, + } }) } })) diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs index 82ea7905fe..a39ffc5f5d 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs @@ -337,12 +337,14 @@ impl BlobServiceClient { let bytes = body.collect().await?; let res: ListContainersSegmentResponse = xml::read_xml(&bytes)?; let rsp = Response::from_bytes(status, headers, bytes); - Ok(match res.next_marker { - Some(next_marker) => PagerResult::Continue { + let next_marker = res.next_marker.unwrap_or_default(); + Ok(if next_marker.is_empty() { + PagerResult::Complete { response: rsp } + } else { + PagerResult::Continue { response: rsp, continuation: next_marker, - }, - None => PagerResult::Complete { response: rsp }, + } }) } })) diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs index 939ea27285..4c3380885c 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs @@ -304,7 +304,7 @@ impl BlockBlobClient { if let Some(transactional_content_md5) = options.transactional_content_md5 { request.insert_header("content-md5", base64::encode(transactional_content_md5)); } - request.insert_header("content-type", "application/octet-stream"); + request.insert_header("content-type", "application/xml"); if let Some(if_match) = options.if_match { request.insert_header("if-match", if_match); } diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs index d748bba9d0..5e2ffc6ba9 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs @@ -123,7 +123,7 @@ impl PageBlobClient { let mut request = Request::new(url, Method::Put); request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); - request.insert_header("content-type", "application/octet-stream"); + request.insert_header("content-type", "application/xml"); if let Some(if_match) = options.if_match { request.insert_header("if-match", if_match); } @@ -276,7 +276,7 @@ impl PageBlobClient { let mut request = Request::new(url, Method::Put); request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); - request.insert_header("content-type", "application/octet-stream"); + request.insert_header("content-type", ""); if let Some(if_match) = options.if_match { request.insert_header("if-match", if_match); } @@ -805,7 +805,7 @@ impl PageBlobClient { let mut request = Request::new(url, Method::Put); request.insert_header("accept", "application/json"); request.insert_header("content-length", content_length.to_string()); - request.insert_header("content-type", "application/octet-stream"); + request.insert_header("content-type", "application/xml"); if let Some(if_match) = options.if_match { request.insert_header("if-match", if_match); } diff --git a/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs b/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs index 67199a0d6a..221c9f984e 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs @@ -6,9 +6,9 @@ use super::{ models_serde, xml_helpers::{ - Blob_itemsBlob, Blob_prefixesBlobPrefix, Blob_tag_setTag, BlobsBlob, Clear_rangeClearRange, - Committed_blocksBlock, Container_itemsContainer, CorsCorsRule, Page_rangePageRange, - SchemaField, Uncommitted_blocksBlock, + Blob_tag_setTag, BlobsBlob, Clear_rangeClearRange, Committed_blocksBlock, + Container_itemsContainer, CorsCorsRule, Page_rangePageRange, SchemaField, + Uncommitted_blocksBlock, }, AccessTier, ArchiveStatus, BlobImmutabilityPolicyMode, BlobType, CopyStatus, GeoReplicationStatusType, LeaseDuration, LeaseState, LeaseStatus, PublicAccessType, @@ -214,42 +214,24 @@ pub struct BlobContainerClientSetAccessPolicyResult; /// The blob flat list segment. #[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] #[non_exhaustive] -#[serde(rename = "Blobs")] #[typespec(format = "xml")] pub struct BlobFlatListSegment { /// The blob items. - #[serde( - default, - deserialize_with = "Blob_itemsBlob::unwrap", - rename = "BlobItems", - serialize_with = "Blob_itemsBlob::wrap" - )] + #[serde(default, rename = "Blob")] pub blob_items: Vec, } /// Represents an array of blobs. #[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] #[non_exhaustive] -#[serde(rename = "Blobs")] #[typespec(format = "xml")] pub struct BlobHierarchyListSegment { /// The blob items - #[serde( - default, - deserialize_with = "Blob_itemsBlob::unwrap", - rename = "BlobItems", - serialize_with = "Blob_itemsBlob::wrap" - )] + #[serde(default, rename = "Blob")] pub blob_items: Vec, /// The blob prefixes. - #[serde( - default, - deserialize_with = "Blob_prefixesBlobPrefix::unwrap", - rename = "BlobPrefixes", - serialize_with = "Blob_prefixesBlobPrefix::wrap", - skip_serializing_if = "Option::is_none" - )] + #[serde(rename = "BlobPrefix", skip_serializing_if = "Option::is_none")] pub blob_prefixes: Option>, } @@ -1009,7 +991,7 @@ pub struct ListBlobsFlatSegmentResponse { pub prefix: Option, /// The blob segment. - #[serde(default)] + #[serde(default, rename = "Blobs")] pub segment: BlobFlatListSegment, /// The service endpoint. @@ -1048,7 +1030,7 @@ pub struct ListBlobsHierarchySegmentResponse { pub prefix: Option, /// The blob segment. - #[serde(default)] + #[serde(default, rename = "Blobs")] pub segment: BlobHierarchyListSegment, /// The service endpoint. diff --git a/sdk/storage/azure_storage_blob/src/generated/models/xml_helpers.rs b/sdk/storage/azure_storage_blob/src/generated/models/xml_helpers.rs index f20d4a15ef..fa9a828573 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/xml_helpers.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/xml_helpers.rs @@ -7,63 +7,10 @@ #![allow(non_snake_case)] use super::{ - ArrowField, BlobItemInternal, BlobPrefix, BlobTag, Block, ClearRange, ContainerItem, CorsRule, - FilterBlobItem, PageRange, + ArrowField, BlobTag, Block, ClearRange, ContainerItem, CorsRule, FilterBlobItem, PageRange, }; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[derive(Deserialize, Serialize)] -#[serde(rename = "BlobItems")] -pub(crate) struct Blob_itemsBlob { - #[serde(default)] - Blob: Vec, -} - -impl Blob_itemsBlob { - pub fn unwrap<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - Ok(Blob_itemsBlob::deserialize(deserializer)?.Blob) - } - - pub fn wrap(to_serialize: &Vec, serializer: S) -> Result - where - S: Serializer, - { - Blob_itemsBlob { - Blob: to_serialize.to_owned(), - } - .serialize(serializer) - } -} - -#[derive(Deserialize, Serialize)] -#[serde(rename = "BlobPrefixes")] -pub(crate) struct Blob_prefixesBlobPrefix { - #[serde(default)] - BlobPrefix: Option>, -} - -impl Blob_prefixesBlobPrefix { - pub fn unwrap<'de, D>(deserializer: D) -> Result>, D::Error> - where - D: Deserializer<'de>, - { - Ok(Blob_prefixesBlobPrefix::deserialize(deserializer)?.BlobPrefix) - } - - pub fn wrap(to_serialize: &Option>, serializer: S) -> Result - where - S: Serializer, - { - Blob_prefixesBlobPrefix { - BlobPrefix: to_serialize.to_owned(), - } - .serialize(serializer) - } -} - #[derive(Deserialize, Serialize)] #[serde(rename = "TagSet")] pub(crate) struct Blob_tag_setTag { diff --git a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs index 3057d1c6c7..7067aa92b4 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -use azure_core::http::{Pager, PagerResult, RequestContent, StatusCode}; +use azure_core::http::StatusCode; use azure_core_test::{recorded, TestContext}; use azure_storage_blob::models::{ - BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientSetMetadataOptions, - LeaseState, ListBlobsFlatSegmentResponse, + BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientListBlobFlatSegmentOptions, + BlobContainerClientSetMetadataOptions, BlobType, LeaseState, }; -use azure_storage_blob_test::get_container_client; +use azure_storage_blob_test::{create_test_blob, get_container_client}; use futures::TryStreamExt; use std::{collections::HashMap, error::Error}; @@ -89,36 +89,22 @@ async fn test_list_blobs(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, false).await?; - let blob_client_1 = container_client.blob_client("testblob1".to_string()); - let blob_client_2 = container_client.blob_client("testblob2".to_string()); + let blob_names = ["testblob1".to_string(), "testblob2".to_string()]; container_client.create_container(None).await?; - let data = b"hello rusty world"; - blob_client_1 - .upload( - RequestContent::from(data.to_vec()), - false, - u64::try_from(data.len())?, - None, - ) - .await?; - blob_client_2 - .upload( - RequestContent::from(data.to_vec()), - false, - u64::try_from(data.len())?, - None, - ) - .await?; + create_test_blob(&container_client.blob_client(blob_names[0].clone())).await?; + create_test_blob(&container_client.blob_client(blob_names[1].clone())).await?; let mut list_blobs_response = container_client.list_blobs(None).await?; - while let Some(page) = list_blobs_response.try_next().await? { - let list_blob_segment_response = page.into_body().await?; - let blob_list = list_blob_segment_response.segment.blob_items; - for blob in blob_list { - println!("{}", blob.name.unwrap().content.unwrap()) - } + let page = list_blobs_response.try_next().await?; + let list_blob_segment_response = page.unwrap().into_body().await?; + let blob_list = list_blob_segment_response.segment.blob_items; + for blob in blob_list { + let blob_name = blob.name.unwrap().content.unwrap(); + let blob_type = blob.properties.unwrap().blob_type.unwrap(); + assert!(blob_names.contains(&blob_name)); + assert_eq!(BlobType::BlockBlob, blob_type); } container_client.delete_container(None).await?; @@ -126,50 +112,62 @@ async fn test_list_blobs(ctx: TestContext) -> Result<(), Box> { } #[recorded::test] -async fn test_list_blobs_2(ctx: TestContext) -> Result<(), Box> { +async fn test_list_blobs_with_continuation(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, false).await?; - let blob_client_1 = container_client.blob_client("testblob1".to_string()); - let blob_client_2 = container_client.blob_client("testblob2".to_string()); + let blob_names = [ + "testblob1".to_string(), + "testblob2".to_string(), + "testblob3".to_string(), + "testblob4".to_string(), + ]; container_client.create_container(None).await?; - let data = b"hello rusty world"; - blob_client_1 - .upload( - RequestContent::from(data.to_vec()), - false, - u64::try_from(data.len())?, - None, - ) - .await?; - blob_client_2 - .upload( - RequestContent::from(data.to_vec()), - false, - u64::try_from(data.len())?, - None, - ) + create_test_blob(&container_client.blob_client(blob_names[0].clone())).await?; + create_test_blob(&container_client.blob_client(blob_names[1].clone())).await?; + create_test_blob(&container_client.blob_client(blob_names[2].clone())).await?; + create_test_blob(&container_client.blob_client(blob_names[3].clone())).await?; + + // First Page + let list_blobs_options = BlobContainerClientListBlobFlatSegmentOptions { + maxresults: Some(2), + ..Default::default() + }; + let mut list_blobs_response = container_client + .list_blobs(Some(list_blobs_options)) .await?; + let first_page = list_blobs_response.try_next().await?; + let list_blob_segment_response = first_page.unwrap().into_body().await?; + let continuation_token = list_blob_segment_response.next_marker; + let blob_list = list_blob_segment_response.segment.blob_items; + assert_eq!(2, blob_list.len()); + for blob in blob_list { + let blob_name = blob.name.unwrap().content.unwrap(); + println!("1st page: {}", blob_name.clone()); + let blob_type = blob.properties.unwrap().blob_type.unwrap(); + assert!(blob_names.contains(&blob_name)); + assert_eq!(BlobType::BlockBlob, blob_type); + } - let mut list_blobs_response = container_client.list_blobs(None).await?; - let mut count = 0; - - while let Some(page) = list_blobs_response.try_next().await? { - println!("while: {}", count); - count += 1; - let list_blob_segment_response = page.into_body().await?; - let blob_list = list_blob_segment_response.segment.blob_items; - - // for blob in blob_list { - // println!("inside of inner for-loop"); - // println!("{}", blob.name.unwrap().content.unwrap()) - // } - - let first_slice = blob_list.first(); - println!("Is this some? {}", first_slice.is_some()); - - println!("bottom of outer while-loop reached") + // Second Page + let list_blobs_options = BlobContainerClientListBlobFlatSegmentOptions { + marker: continuation_token, + ..Default::default() + }; + let mut list_blobs_response = container_client + .list_blobs(Some(list_blobs_options)) + .await?; + let second_page = list_blobs_response.try_next().await?; + let list_blob_segment_response = second_page.unwrap().into_body().await?; + let blob_list = list_blob_segment_response.segment.blob_items; + assert_eq!(2, blob_list.len()); + for blob in blob_list { + let blob_name = blob.name.unwrap().content.unwrap(); + println!("2nd page: {}", blob_name.clone()); + let blob_type = blob.properties.unwrap().blob_type.unwrap(); + assert!(blob_names.contains(&blob_name)); + assert_eq!(BlobType::BlockBlob, blob_type); } container_client.delete_container(None).await?; diff --git a/sdk/storage/azure_storage_blob/tsp-location.yaml b/sdk/storage/azure_storage_blob/tsp-location.yaml index 2317872844..630396183b 100644 --- a/sdk/storage/azure_storage_blob/tsp-location.yaml +++ b/sdk/storage/azure_storage_blob/tsp-location.yaml @@ -1,4 +1,4 @@ directory: specification/storage/Microsoft.BlobStorage -commit: 566f9855e2272ffe7d575e560d95f4755b5b0fb5 +commit: a0463864e021c00771eb01510e2eecd800ad05e2 repo: Azure/azure-rest-api-specs additionalDirectories: From 14ff4c3ee40a965d2f30b9ca145bc739d5730f9d Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Thu, 29 May 2025 14:06:31 -0700 Subject: [PATCH 6/8] PR feedback, attempt at discrete next --- .../src/clients/blob_container_client.rs | 2 +- .../tests/blob_container_client.rs | 84 +++++++++++++++++-- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs index 48963a72f7..d540205c80 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs @@ -151,7 +151,7 @@ impl BlobContainerClient { /// # Arguments /// /// * `options` - Optional configuration for the request. - pub async fn list_blobs( + pub fn list_blobs( &self, options: Option>, ) -> Result> { diff --git a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs index 7067aa92b4..aa7e7b9379 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs @@ -8,7 +8,7 @@ use azure_storage_blob::models::{ BlobContainerClientSetMetadataOptions, BlobType, LeaseState, }; use azure_storage_blob_test::{create_test_blob, get_container_client}; -use futures::TryStreamExt; +use futures::{StreamExt, TryStreamExt}; use std::{collections::HashMap, error::Error}; #[recorded::test] @@ -95,7 +95,7 @@ async fn test_list_blobs(ctx: TestContext) -> Result<(), Box> { create_test_blob(&container_client.blob_client(blob_names[0].clone())).await?; create_test_blob(&container_client.blob_client(blob_names[1].clone())).await?; - let mut list_blobs_response = container_client.list_blobs(None).await?; + let mut list_blobs_response = container_client.list_blobs(None)?; let page = list_blobs_response.try_next().await?; let list_blob_segment_response = page.unwrap().into_body().await?; @@ -112,7 +112,9 @@ async fn test_list_blobs(ctx: TestContext) -> Result<(), Box> { } #[recorded::test] -async fn test_list_blobs_with_continuation(ctx: TestContext) -> Result<(), Box> { +async fn test_list_blobs_with_continuation_try_next( + ctx: TestContext, +) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, false).await?; @@ -134,9 +136,7 @@ async fn test_list_blobs_with_continuation(ctx: TestContext) -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { + // Recording Setup + + let recording = ctx.recording(); + let container_client = get_container_client(recording, false).await?; + let blob_names = [ + "testblob1".to_string(), + "testblob2".to_string(), + "testblob3".to_string(), + "testblob4".to_string(), + ]; + + container_client.create_container(None).await?; + create_test_blob(&container_client.blob_client(blob_names[0].clone())).await?; + create_test_blob(&container_client.blob_client(blob_names[1].clone())).await?; + create_test_blob(&container_client.blob_client(blob_names[2].clone())).await?; + create_test_blob(&container_client.blob_client(blob_names[3].clone())).await?; + + let list_blobs_options = BlobContainerClientListBlobFlatSegmentOptions { + maxresults: Some(2), + ..Default::default() + }; + let mut pager_response = container_client.list_blobs(Some(list_blobs_options))?; + let mut page_count = 0; + + while let Some(page) = pager_response.next().await { + page_count += 1; + let current_page = page.unwrap().into_body().await?; + match page_count { + 1 => { + let blob_list = current_page.segment.blob_items; + assert_eq!(2, blob_list.len()); + + let mut first_loop_counter = 0; + for blob in blob_list { + first_loop_counter += 1; + println!("First loop: {}", first_loop_counter); + let blob_name = blob.name.unwrap().content.unwrap(); + let blob_type = blob.properties.unwrap().blob_type.unwrap(); + assert!(blob_names.contains(&blob_name)); + assert_eq!(BlobType::BlockBlob, blob_type); + } + } + 2 => { + let blob_list = current_page.segment.blob_items; + assert_eq!(2, blob_list.len()); + + let mut second_loop_counter = 0; + for blob in blob_list { + second_loop_counter += 1; + println!("Second loop loop: {}", second_loop_counter); + let blob_name = blob.name.unwrap().content.unwrap(); + let blob_type = blob.properties.unwrap().blob_type.unwrap(); + assert!(blob_names.contains(&blob_name)); + assert_eq!(BlobType::BlockBlob, blob_type); + } + } + _ => { + panic!("Unexpected page number reached.") + } + } + } + + container_client.delete_container(None).await?; + Ok(()) +} From 779935acd34d8dd363d1b75f5224157a57527d99 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Thu, 29 May 2025 14:53:09 -0700 Subject: [PATCH 7/8] Fix test recordings, PR feedback --- sdk/storage/assets.json | 2 +- .../tests/blob_container_client.rs | 49 +++---------------- 2 files changed, 8 insertions(+), 43 deletions(-) diff --git a/sdk/storage/assets.json b/sdk/storage/assets.json index 0414da4f2c..f749f6b24a 100644 --- a/sdk/storage/assets.json +++ b/sdk/storage/assets.json @@ -1,6 +1,6 @@ { "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "rust", - "Tag": "rust/azure_storage_blob_cdaf5c2731", + "Tag": "rust/azure_storage_blob_231754d877", "TagPrefix": "rust/azure_storage_blob" } \ No newline at end of file diff --git a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs index aa7e7b9379..43b8f7a45d 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs @@ -100,7 +100,10 @@ async fn test_list_blobs(ctx: TestContext) -> Result<(), Box> { let page = list_blobs_response.try_next().await?; let list_blob_segment_response = page.unwrap().into_body().await?; let blob_list = list_blob_segment_response.segment.blob_items; + let mut counter = 0; for blob in blob_list { + counter += 1; + println!("Entered the loop: {} times", counter); let blob_name = blob.name.unwrap().content.unwrap(); let blob_type = blob.properties.unwrap().blob_type.unwrap(); assert!(blob_names.contains(&blob_name)); @@ -112,9 +115,7 @@ async fn test_list_blobs(ctx: TestContext) -> Result<(), Box> { } #[recorded::test] -async fn test_list_blobs_with_continuation_try_next( - ctx: TestContext, -) -> Result<(), Box> { +async fn test_list_blobs_with_continuation(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, false).await?; @@ -131,7 +132,7 @@ async fn test_list_blobs_with_continuation_try_next( create_test_blob(&container_client.blob_client(blob_names[2].clone())).await?; create_test_blob(&container_client.blob_client(blob_names[3].clone())).await?; - // First Page + // Continuation Token with Token Provided let list_blobs_options = BlobContainerClientListBlobFlatSegmentOptions { maxresults: Some(2), ..Default::default() @@ -144,57 +145,27 @@ async fn test_list_blobs_with_continuation_try_next( assert_eq!(2, blob_list.len()); for blob in blob_list { let blob_name = blob.name.unwrap().content.unwrap(); - println!("1st page: {}", blob_name.clone()); let blob_type = blob.properties.unwrap().blob_type.unwrap(); assert!(blob_names.contains(&blob_name)); assert_eq!(BlobType::BlockBlob, blob_type); } - - // Second Page let list_blobs_options = BlobContainerClientListBlobFlatSegmentOptions { marker: continuation_token, ..Default::default() }; - let mut list_blobs_response = container_client.list_blobs(Some(list_blobs_options))?; + let mut list_blobs_response = container_client.list_blobs(Some(list_blobs_options.clone()))?; let second_page = list_blobs_response.try_next().await?; let list_blob_segment_response = second_page.unwrap().into_body().await?; let blob_list = list_blob_segment_response.segment.blob_items; assert_eq!(2, blob_list.len()); for blob in blob_list { let blob_name = blob.name.unwrap().content.unwrap(); - println!("2nd page: {}", blob_name.clone()); let blob_type = blob.properties.unwrap().blob_type.unwrap(); assert!(blob_names.contains(&blob_name)); assert_eq!(BlobType::BlockBlob, blob_type); } - container_client.delete_container(None).await?; - Ok(()) -} - -#[recorded::test] -async fn test_list_blobs_with_continuation_next(ctx: TestContext) -> Result<(), Box> { - // Recording Setup - - let recording = ctx.recording(); - let container_client = get_container_client(recording, false).await?; - let blob_names = [ - "testblob1".to_string(), - "testblob2".to_string(), - "testblob3".to_string(), - "testblob4".to_string(), - ]; - - container_client.create_container(None).await?; - create_test_blob(&container_client.blob_client(blob_names[0].clone())).await?; - create_test_blob(&container_client.blob_client(blob_names[1].clone())).await?; - create_test_blob(&container_client.blob_client(blob_names[2].clone())).await?; - create_test_blob(&container_client.blob_client(blob_names[3].clone())).await?; - - let list_blobs_options = BlobContainerClientListBlobFlatSegmentOptions { - maxresults: Some(2), - ..Default::default() - }; + // Continuation Token, Automatic Paging let mut pager_response = container_client.list_blobs(Some(list_blobs_options))?; let mut page_count = 0; @@ -206,10 +177,7 @@ async fn test_list_blobs_with_continuation_next(ctx: TestContext) -> Result<(), let blob_list = current_page.segment.blob_items; assert_eq!(2, blob_list.len()); - let mut first_loop_counter = 0; for blob in blob_list { - first_loop_counter += 1; - println!("First loop: {}", first_loop_counter); let blob_name = blob.name.unwrap().content.unwrap(); let blob_type = blob.properties.unwrap().blob_type.unwrap(); assert!(blob_names.contains(&blob_name)); @@ -220,10 +188,7 @@ async fn test_list_blobs_with_continuation_next(ctx: TestContext) -> Result<(), let blob_list = current_page.segment.blob_items; assert_eq!(2, blob_list.len()); - let mut second_loop_counter = 0; for blob in blob_list { - second_loop_counter += 1; - println!("Second loop loop: {}", second_loop_counter); let blob_name = blob.name.unwrap().content.unwrap(); let blob_type = blob.properties.unwrap().blob_type.unwrap(); assert!(blob_names.contains(&blob_name)); From c591da2e26d571d6bd87388e4351a73243d4e44b Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 30 May 2025 17:20:17 -0700 Subject: [PATCH 8/8] PR feedback, moved futures to dev-dependencies --- sdk/storage/azure_storage_blob/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure_storage_blob/Cargo.toml b/sdk/storage/azure_storage_blob/Cargo.toml index 0280f26bc5..a3b26a89a1 100644 --- a/sdk/storage/azure_storage_blob/Cargo.toml +++ b/sdk/storage/azure_storage_blob/Cargo.toml @@ -18,7 +18,6 @@ categories = ["api-bindings"] [dependencies] async-trait.workspace = true azure_core = { workspace = true, features = ["xml"] } -futures.workspace = true serde.workspace = true time.workspace = true typespec_client_core = { workspace = true, features = ["derive"] } @@ -32,4 +31,5 @@ workspace = true azure_core_test.workspace = true azure_identity.workspace = true azure_storage_blob_test.path = "../azure_storage_blob_test" +futures.workspace = true tokio = { workspace = true, features = ["macros"] }