diff --git a/eng/emitter-package-lock.json b/eng/emitter-package-lock.json index 3c1c6054132..b0715b992c7 100644 --- a/eng/emitter-package-lock.json +++ b/eng/emitter-package-lock.json @@ -5,18 +5,18 @@ "packages": { "": { "dependencies": { - "@azure-tools/typespec-rust": "0.24.0" + "@azure-tools/typespec-rust": "0.24.1" }, "devDependencies": { - "@azure-tools/typespec-azure-core": "0.60", - "@azure-tools/typespec-azure-rulesets": "0.60", - "@azure-tools/typespec-client-generator-core": "0.60", - "@typespec/compiler": "1.4", - "@typespec/http": "1.4", - "@typespec/openapi": "1.4", - "@typespec/rest": "0.74", - "@typespec/versioning": "0.74", - "@typespec/xml": "0.74" + "@azure-tools/typespec-azure-core": "~0.61", + "@azure-tools/typespec-azure-rulesets": "~0.61", + "@azure-tools/typespec-client-generator-core": ">=0.61.1", + "@typespec/compiler": "^1.4.0", + "@typespec/http": "^1.4.0", + "@typespec/openapi": "^1.4.0", + "@typespec/rest": "~0.75.0", + "@typespec/versioning": "~0.75.0", + "@typespec/xml": "~0.75.0" } }, "node_modules/@azure-tools/async-io": { @@ -65,24 +65,23 @@ } }, "node_modules/@azure-tools/typespec-azure-core": { - "version": "0.60.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.60.0.tgz", - "integrity": "sha512-Pmm7blxnEZZ7lhMJWWsiIqMrFthaCK6uu7f+ONN7dq0Mjc/O9w8+43tAIXwnGz1OKAWmiToh3EDbaxeWyt/FhQ==", + "version": "0.61.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.61.0.tgz", + "integrity": "sha512-sqOYBUghAtVMBiAWwT3fMRVSDNwR7IU3AQ96n/ErhAthwWjTe7PFVfK/MPjpI1mO3cdyLeS2DGyI3gt/waWP4g==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0", - "@typespec/http": "^1.4.0", - "@typespec/rest": "^0.74.0" + "@typespec/compiler": "^1.5.0", + "@typespec/http": "^1.5.0", + "@typespec/rest": "^0.75.0" } }, "node_modules/@azure-tools/typespec-azure-resource-manager": { - "version": "0.60.1", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-resource-manager/-/typespec-azure-resource-manager-0.60.1.tgz", - "integrity": "sha512-MEmI7NXNRddHYFzzXNH0Y1Izr2tCbJdAgh3LfufM2k8oRiIsXxxQ+n2UDReCAxDQeExFT8pqDq32A9AhL9pNJw==", + "version": "0.61.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-resource-manager/-/typespec-azure-resource-manager-0.61.0.tgz", + "integrity": "sha512-m/M6AareRXacDwyR82g9DqMppfX0eEsv0/q4PW2Lii7wGVzFiiU6fLqsiWBdIHl7GaKszTRtZXNRk/IL9HV8Lw==", "dev": true, "license": "MIT", "peer": true, @@ -94,36 +93,35 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.60.0", - "@typespec/compiler": "^1.4.0", - "@typespec/http": "^1.4.0", - "@typespec/openapi": "^1.4.0", - "@typespec/rest": "^0.74.0", - "@typespec/versioning": "^0.74.0" + "@azure-tools/typespec-azure-core": "^0.61.0", + "@typespec/compiler": "^1.5.0", + "@typespec/http": "^1.5.0", + "@typespec/openapi": "^1.5.0", + "@typespec/rest": "^0.75.0", + "@typespec/versioning": "^0.75.0" } }, "node_modules/@azure-tools/typespec-azure-rulesets": { - "version": "0.60.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-rulesets/-/typespec-azure-rulesets-0.60.0.tgz", - "integrity": "sha512-4sx9StBWkmnBfLJ9b23RSwCs0TkTElaU9+6a/cS6JS0F7UggP/KLQd6LG59D0u9ByXM2x9pvYPO8l/K7UOXoPg==", + "version": "0.61.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-rulesets/-/typespec-azure-rulesets-0.61.0.tgz", + "integrity": "sha512-EWArbj6dgTz7Xi0mAkp0ru6PoWqfXLHlk8Kt7BzVcHCPojBYK14JW9RYSxBta+h2fAEQTSQu+X1r7Y7PhJE8rA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.60.0", - "@azure-tools/typespec-azure-resource-manager": "^0.60.0", - "@azure-tools/typespec-client-generator-core": "^0.60.0", - "@typespec/compiler": "^1.4.0" + "@azure-tools/typespec-azure-core": "^0.61.0", + "@azure-tools/typespec-azure-resource-manager": "^0.61.0", + "@azure-tools/typespec-client-generator-core": "^0.61.0", + "@typespec/compiler": "^1.5.0" } }, "node_modules/@azure-tools/typespec-client-generator-core": { - "version": "0.60.3", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.60.3.tgz", - "integrity": "sha512-gcaLRoAJnvqg2tNyEYk+vOMhyP0PJpoZZERuDPB9VLiAAdxl3eTz22vAa3wKvnGFpLDxuvo4+ootEYguRCiwdg==", + "version": "0.61.2", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.61.2.tgz", + "integrity": "sha512-q+fktD/LZjiKYZbQHzWOMZd5Zqdr7PU0Cn9GEMkwv5gIvCPhT2Qxpgig7lPnMVYFwGmc+2qBZk1FjJPin0DUrw==", "license": "MIT", - "peer": true, "dependencies": { "change-case": "~5.4.4", "pluralize": "^8.0.0", @@ -133,22 +131,22 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.60.0", - "@typespec/compiler": "^1.4.0", - "@typespec/events": "^0.74.0", - "@typespec/http": "^1.4.0", - "@typespec/openapi": "^1.4.0", - "@typespec/rest": "^0.74.0", - "@typespec/sse": "^0.74.0", - "@typespec/streams": "^0.74.0", - "@typespec/versioning": "^0.74.0", - "@typespec/xml": "^0.74.0" + "@azure-tools/typespec-azure-core": "^0.61.0", + "@typespec/compiler": "^1.5.0", + "@typespec/events": "^0.75.0", + "@typespec/http": "^1.5.0", + "@typespec/openapi": "^1.5.0", + "@typespec/rest": "^0.75.0", + "@typespec/sse": "^0.75.0", + "@typespec/streams": "^0.75.0", + "@typespec/versioning": "^0.75.0", + "@typespec/xml": "^0.75.0" } }, "node_modules/@azure-tools/typespec-rust": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-rust/-/typespec-rust-0.24.0.tgz", - "integrity": "sha512-V4MfcjSY2NWe2QSHNpl2Vp9yY3Wpmyio2+iGDk16PwVXhE4sdUtASZZysQI2LY0eTzZHp/AKe+qoTx8oA4UsSQ==", + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-rust/-/typespec-rust-0.24.1.tgz", + "integrity": "sha512-8rpyMBjocz6iM1wruXmkMIi9t/DC7MwX5u9Uad2o6KbPOHn8tk8k7agDa0wVE/gid1I8tP3/StA0zLU5auOaFg==", "license": "MIT", "dependencies": { "@azure-tools/codegen": "~2.10.1", @@ -163,7 +161,7 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-client-generator-core": ">=0.60.3 <1.0.0", + "@azure-tools/typespec-client-generator-core": ">=0.61.1 <1.0.0", "@typespec/compiler": "^1.4.0", "@typespec/http": "^1.4.0" } @@ -183,33 +181,33 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@inquirer/ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", - "integrity": "sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", + "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@inquirer/checkbox": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.4.tgz", - "integrity": "sha512-2n9Vgf4HSciFq8ttKXk+qy+GsyTXPV1An6QAwe/8bkbbqvG4VW1I/ZY1pNu2rf+h9bdzMLPbRSfcNxkHBy/Ydw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.0.tgz", + "integrity": "sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/core": "^10.2.2", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -225,13 +223,13 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.18", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.18.tgz", - "integrity": "sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==", + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.19.tgz", + "integrity": "sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -246,14 +244,14 @@ } }, "node_modules/@inquirer/core": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", - "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", + "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", + "@inquirer/ansi": "^1.0.1", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", @@ -273,14 +271,14 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.20", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.20.tgz", - "integrity": "sha512-7omh5y5bK672Q+Brk4HBbnHNowOZwrb/78IFXdrEB9PfdxL3GudQyDk8O9vQ188wj3xrEebS2M9n18BjJoI83g==", + "version": "4.2.21", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.21.tgz", + "integrity": "sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", + "@inquirer/core": "^10.3.0", "@inquirer/external-editor": "^1.0.2", - "@inquirer/type": "^3.0.8" + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -295,13 +293,13 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.20", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.20.tgz", - "integrity": "sha512-Dt9S+6qUg94fEvgn54F2Syf0Z3U8xmnBI9ATq2f5h9xt09fs2IJXSCIXyyVHwvggKWFXEY/7jATRo2K6Dkn6Ow==", + "version": "4.0.21", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.21.tgz", + "integrity": "sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8", + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -338,22 +336,22 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", - "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", + "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@inquirer/input": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.4.tgz", - "integrity": "sha512-cwSGpLBMwpwcZZsc6s1gThm0J+it/KIJ+1qFL2euLmSKUMGumJ5TcbMgxEjMjNHRGadouIYbiIgruKoDZk7klw==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.5.tgz", + "integrity": "sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -368,13 +366,13 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.20", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.20.tgz", - "integrity": "sha512-bbooay64VD1Z6uMfNehED2A2YOPHSJnQLs9/4WNiV/EK+vXczf/R988itL2XLDGTgmhMF2KkiWZo+iEZmc4jqg==", + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.21.tgz", + "integrity": "sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -389,14 +387,14 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.20", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.20.tgz", - "integrity": "sha512-nxSaPV2cPvvoOmRygQR+h0B+Av73B01cqYLcr7NXcGXhbmsYfUb8fDdw2Us1bI2YsX+VvY7I7upgFYsyf8+Nug==", + "version": "4.0.21", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.21.tgz", + "integrity": "sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -411,21 +409,21 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.6.tgz", - "integrity": "sha512-68JhkiojicX9SBUD8FE/pSKbOKtwoyaVj1kwqLfvjlVXZvOy3iaSWX4dCLsZyYx/5Ur07Fq+yuDNOen+5ce6ig==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.9.0.tgz", + "integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==", "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.2.4", - "@inquirer/confirm": "^5.1.18", - "@inquirer/editor": "^4.2.20", - "@inquirer/expand": "^4.0.20", - "@inquirer/input": "^4.2.4", - "@inquirer/number": "^3.0.20", - "@inquirer/password": "^4.0.20", - "@inquirer/rawlist": "^4.1.8", - "@inquirer/search": "^3.1.3", - "@inquirer/select": "^4.3.4" + "@inquirer/checkbox": "^4.3.0", + "@inquirer/confirm": "^5.1.19", + "@inquirer/editor": "^4.2.21", + "@inquirer/expand": "^4.0.21", + "@inquirer/input": "^4.2.5", + "@inquirer/number": "^3.0.21", + "@inquirer/password": "^4.0.21", + "@inquirer/rawlist": "^4.1.9", + "@inquirer/search": "^3.2.0", + "@inquirer/select": "^4.4.0" }, "engines": { "node": ">=18" @@ -440,13 +438,13 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.8.tgz", - "integrity": "sha512-CQ2VkIASbgI2PxdzlkeeieLRmniaUU1Aoi5ggEdm6BIyqopE9GuDXdDOj9XiwOqK5qm72oI2i6J+Gnjaa26ejg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.9.tgz", + "integrity": "sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8", + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -462,14 +460,14 @@ } }, "node_modules/@inquirer/search": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.3.tgz", - "integrity": "sha512-D5T6ioybJJH0IiSUK/JXcoRrrm8sXwzrVMjibuPs+AgxmogKslaafy1oxFiorNI4s3ElSkeQZbhYQgLqiL8h6Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz", + "integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -485,15 +483,15 @@ } }, "node_modules/@inquirer/select": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.4.tgz", - "integrity": "sha512-Qp20nySRmfbuJBBsgPU7E/cL62Hf250vMZRzYDcBHty2zdD1kKCnoDFWRr0WO2ZzaXp3R7a4esaVGJUx0E6zvA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.0.tgz", + "integrity": "sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/core": "^10.2.2", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -509,9 +507,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", - "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", + "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", "license": "MIT", "engines": { "node": ">=18" @@ -591,17 +589,16 @@ } }, "node_modules/@types/turndown": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.5.tgz", - "integrity": "sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.6.tgz", + "integrity": "sha512-ru00MoyeeouE5BX4gRL+6m/BsDfbRayOskWqUvh7CLGW+UXxHQItqALa38kKnOiZPqJrtzJUgAC2+F0rL1S4Pg==", "license": "MIT" }, "node_modules/@typespec/compiler": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.4.0.tgz", - "integrity": "sha512-/AFiU3ImuhH/vHKzSGv7I2peewdJ7YLhgMCfFDNk6Ae0a5Ylrc8R1GOATVilisEPBFG9lnjHn3uUcyaZs5VWRw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.5.0.tgz", + "integrity": "sha512-REJgZOEZ9g9CC72GGT0+nLbjW+5WVlCfm1d6w18N5RsUo7vLXs8IPXwq7xZJzoqU99Q9B4keqzPuTU4OrDUTrA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "~7.27.1", "@inquirer/prompts": "^7.4.0", @@ -630,30 +627,29 @@ } }, "node_modules/@typespec/events": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.74.0.tgz", - "integrity": "sha512-CY6JTtheMKAUlxiPmwx2fLIAWEwezsXmQYUMRhyuW44Q73unQIkexE43LUnNWOJSZckYucqUp+ihXh7jxzWeVQ==", + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.75.0.tgz", + "integrity": "sha512-V7unXnj+sZoa/1wQG8G6x2TiQqotx18S/qFbDzdfJRPCVpH/Z3xIpppce4jTZALXT97tKZK5GDHijn2zWuWWxg==", "license": "MIT", "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0" + "@typespec/compiler": "^1.5.0" } }, "node_modules/@typespec/http": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.4.0.tgz", - "integrity": "sha512-Y0PDDtBu+oZnwivfhbL0lN6Mk3QiCxZ66DgB5kFjcgKNpnXf0u440PPyaL42a8lbchzz5lVwz+cinyIMI89FIQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.5.0.tgz", + "integrity": "sha512-52XLXwqSY2SY6nSvfkiTsNiJzlMeIAZ6MFIVJ5YkoibA21TNAP4DtjTZgC2GieZLY2NNN/rqDCqBX+DyWqTrfQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0", - "@typespec/streams": "^0.74.0" + "@typespec/compiler": "^1.5.0", + "@typespec/streams": "^0.75.0" }, "peerDependenciesMeta": { "@typespec/streams": { @@ -662,86 +658,82 @@ } }, "node_modules/@typespec/openapi": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.4.0.tgz", - "integrity": "sha512-ZfrCsmZG/Zt1laLaWC0pKvnZr4jqrm/YS/YuZe/gVrSYKBxGLopXle7H0wrSSMYkIVCNCLiC68/HqRxV6XTfoA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.5.0.tgz", + "integrity": "sha512-27sXkSK2r1sAmVMLv+pwlN/Cm+yg9nEK8iuGyJRuEkBk7hcsJDbTnBlsEvlRTI8DqljtzA7YECDHBLK88zZHeg==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0", - "@typespec/http": "^1.4.0" + "@typespec/compiler": "^1.5.0", + "@typespec/http": "^1.5.0" } }, "node_modules/@typespec/rest": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.74.0.tgz", - "integrity": "sha512-dE+Xmv01AQ7m8jUvEbGsUQLSVo3sLzMpnHRbQEOnJX42oDqtIsz/2GEOXKQpNm1AKBISK66E2FFB5boz999Ziw==", + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.75.0.tgz", + "integrity": "sha512-rQ+RP0kcrKWjbpCIkBd8hpxYSNc3CfQxl0MLP1+MYGRHlHL8ss4xbwdANIYZXZZ2i2Hqt19B7cEUGD4MLoCHvw==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0", - "@typespec/http": "^1.4.0" + "@typespec/compiler": "^1.5.0", + "@typespec/http": "^1.5.0" } }, "node_modules/@typespec/sse": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.74.0.tgz", - "integrity": "sha512-+m7/elbGp7q/kqCGaBRj8v8wVMWKVEV8AsZOjf1PY2MkMUrux9ivOijBIktgoLBXDn+ocO2qVfFrHWG2slZSaw==", + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.75.0.tgz", + "integrity": "sha512-8iODUY3C/0hR9sTzyHeTgYfZkKeqZM+/P0OmN1ZWlLUokXQ67yydGXIqnjl+yaeuntwN8H2DDwLguU15c+j+UQ==", "license": "MIT", "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0", - "@typespec/events": "^0.74.0", - "@typespec/http": "^1.4.0", - "@typespec/streams": "^0.74.0" + "@typespec/compiler": "^1.5.0", + "@typespec/events": "^0.75.0", + "@typespec/http": "^1.5.0", + "@typespec/streams": "^0.75.0" } }, "node_modules/@typespec/streams": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.74.0.tgz", - "integrity": "sha512-LIWizQgzGt8qN8ravte4DrPLPNOk9ge73bV9Us2TOECagTVQWwgMVy7+o/Beff3sOLQO/sEOwfzvmnNpSlauHg==", + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.75.0.tgz", + "integrity": "sha512-ubvxCN+SZwN9aEarz8CPtMJgnopeu8dXyut47q0FAPp9nykmXy7s+dmsopR+7OX0Fhcnh8ZFYTQcJzJ3QftOiQ==", "license": "MIT", "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0" + "@typespec/compiler": "^1.5.0" } }, "node_modules/@typespec/versioning": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.74.0.tgz", - "integrity": "sha512-eFIa23tycWJgv3Lxyu6jUlRi02dhtQE4Jjx3Ui5vEbwHW8pMEzuyF7ALt1c+V9HOLkfDkS4dJkiOVIoikZHPvQ==", + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.75.0.tgz", + "integrity": "sha512-wdLcVx5UW4WRks/OXfqLiaDTtWfAWgv/nj69u99gRJU6iY9ExEvK5x9NQszZQKYnu6tM7nkoYMg4zu+7YBUBaw==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0" + "@typespec/compiler": "^1.5.0" } }, "node_modules/@typespec/xml": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.74.0.tgz", - "integrity": "sha512-NiXatOfpyPxU94f2tEBAygxJeS7CvIr5lvnfZkC0tUHwkiJeLrI1jt13kDVB5CE6zNK6I3d7c37xsQs9WXGFAQ==", + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.75.0.tgz", + "integrity": "sha512-JVafN1nZE3BcQrKbaAFVWw/IleTRdsJpwT3oZ2m7EfWnG30sKtoR9inF9dRoW+XXIjNzCfeYqjkwzEkEnIrCww==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.4.0" + "@typespec/compiler": "^1.5.0" } }, "node_modules/ajv": { @@ -877,9 +869,9 @@ } }, "node_modules/cliui/node_modules/emoji-regex": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", - "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, "node_modules/cliui/node_modules/string-width": { @@ -1444,9 +1436,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1580,9 +1572,9 @@ } }, "node_modules/turndown": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.1.tgz", - "integrity": "sha512-7YiPJw6rLClQL3oUKN3KgMaXeJJ2lAyZItclgKDurqnH61so4k4IH/qwmMva0zpuJc/FhRExBBnk7EbeFANlgQ==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.2.tgz", + "integrity": "sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==", "license": "MIT", "dependencies": { "@mixmark-io/domino": "^2.2.0" @@ -1726,9 +1718,9 @@ } }, "node_modules/yargs/node_modules/emoji-regex": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", - "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, "node_modules/yargs/node_modules/string-width": { diff --git a/eng/emitter-package.json b/eng/emitter-package.json index 4533cef9e6c..52e818a919e 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.24.0" + "@azure-tools/typespec-rust": "0.24.1" }, "devDependencies": { - "@azure-tools/typespec-azure-core": "0.60", - "@azure-tools/typespec-azure-rulesets": "0.60", - "@azure-tools/typespec-client-generator-core": "0.60", - "@typespec/compiler": "1.4", - "@typespec/http": "1.4", - "@typespec/openapi": "1.4", - "@typespec/rest": "0.74", - "@typespec/versioning": "0.74", - "@typespec/xml": "0.74" + "@azure-tools/typespec-azure-core": "~0.61", + "@azure-tools/typespec-azure-rulesets": "~0.61", + "@azure-tools/typespec-client-generator-core": ">=0.61.1", + "@typespec/compiler": "^1.4.0", + "@typespec/http": "^1.4.0", + "@typespec/openapi": "^1.4.0", + "@typespec/rest": "~0.75.0", + "@typespec/versioning": "~0.75.0", + "@typespec/xml": "~0.75.0" } -} \ No newline at end of file +} diff --git a/sdk/eventhubs/assets.json b/sdk/eventhubs/assets.json index cb2d83307ad..de7f203918e 100644 --- a/sdk/eventhubs/assets.json +++ b/sdk/eventhubs/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "rust", "TagPrefix": "rust/eventhubs", - "Tag": "rust/eventhubs_12266aa668" + "Tag": "rust/eventhubs_ad9b84912d" } diff --git a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/README.md b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/README.md index efac88df795..2f4a12d74cf 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/README.md +++ b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/README.md @@ -88,8 +88,8 @@ async fn main() -> Result<(), Box> { let credential = DeveloperToolsCredential::new(None)?; let blob_client = BlobContainerClient::new( "https://yourstorageaccount.blob.core.windows.net", - "yourcontainername".to_string(), - credential.clone(), + "yourcontainername", + Some(credential.clone()), None, )?; diff --git a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/examples/checkpoint_store_basic.rs b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/examples/checkpoint_store_basic.rs index 671e9124f9c..4be62e1c836 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/examples/checkpoint_store_basic.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/examples/checkpoint_store_basic.rs @@ -46,8 +46,8 @@ async fn main() -> Result<(), Box> { // Instantiate a blob client with OpenTelemetry instrumentation enabled let blob_container_client = BlobContainerClient::new( &storage_account_url, - container, - credential, + &container, + Some(credential), Some(BlobContainerClientOptions { client_options: ClientOptions { instrumentation: InstrumentationOptions { diff --git a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/examples/processor_with_blob_checkpoints.rs b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/examples/processor_with_blob_checkpoints.rs index 7da4ddbaa90..ce3161149e4 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/examples/processor_with_blob_checkpoints.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/examples/processor_with_blob_checkpoints.rs @@ -33,8 +33,8 @@ async fn main() -> Result<(), Box> { let credential = DeveloperToolsCredential::new(None)?; let blob_container_client = BlobContainerClient::new( &storage_account_url, - container_name, - credential.clone(), + &container_name, + Some(credential.clone()), None, )?; let consumer = ConsumerClient::builder() diff --git a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/src/checkpoint_store.rs b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/src/checkpoint_store.rs index 179656a6b62..a7bcbebd145 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/src/checkpoint_store.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/src/checkpoint_store.rs @@ -68,9 +68,7 @@ impl BlobCheckpointStore { blob_name: &str, metadata: HashMap, ) -> Result<(Option, Option)> { - let blob_client = self - .blob_container_client - .blob_client(blob_name.to_string()); + let blob_client = self.blob_container_client.blob_client(blob_name); let result = blob_client.set_metadata(metadata.clone(), None).await; match result { @@ -106,9 +104,7 @@ impl BlobCheckpointStore { metadata: Option>, etag: Option, ) -> Result<(Option, Option)> { - let blob_client = self - .blob_container_client - .blob_client(blob_name.to_string()); + let blob_client = self.blob_container_client.blob_client(blob_name); if etag.is_some() { debug!( diff --git a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/tests/checkpoint_unit_tests.rs b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/tests/checkpoint_unit_tests.rs index 9ac679d6e2e..c130577c919 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/tests/checkpoint_unit_tests.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs_checkpointstore_blob/tests/checkpoint_unit_tests.rs @@ -17,8 +17,8 @@ pub fn create_test_checkpoint_store(recording: &Recording) -> Result Result<(), Box> { let credential = DeveloperToolsCredential::new(None)?; let blob_client = BlobClient::new( "https://.blob.core.windows.net/", // endpoint - "container_name".to_string(), // container name - "blob_name".to_string(), // blob name - credential, // credential + "container_name", // container name + "blob_name", // blob name + Some(credential), // credential Some(BlobClientOptions::default()), // BlobClient options )?; Ok(()) @@ -75,9 +75,9 @@ async fn main() -> Result<(), Box> { let credential = DeveloperToolsCredential::new(None)?; let blob_client = BlobClient::new( "https://.blob.core.windows.net/", // endpoint - "container_name".to_string(), // container name - "blob_name".to_string(), // blob name - credential, // credential + "container_name", // container name + "blob_name", // blob name + Some(credential), // credential Some(BlobClientOptions::default()), // BlobClient options )?; Ok(()) @@ -96,9 +96,9 @@ async fn main() -> Result<(), Box> { let credential = DeveloperToolsCredential::new(None)?; let blob_client = BlobClient::new( "https://.blob.core.windows.net/", - "container_name".to_string(), - "blob_name".to_string(), - credential, + "container_name", + "blob_name", + Some(credential), Some(BlobClientOptions::default()), )?; @@ -127,9 +127,9 @@ async fn main() -> Result<(), Box> { let credential = DeveloperToolsCredential::new(None)?; let blob_client = BlobClient::new( "https://.blob.core.windows.net/", - "container_name".to_string(), - "blob_name".to_string(), - credential, + "container_name", + "blob_name", + Some(credential), Some(BlobClientOptions::default()), )?; let blob_properties = blob_client.get_properties( diff --git a/sdk/storage/azure_storage_blob/assets.json b/sdk/storage/azure_storage_blob/assets.json index e095ad34cf2..dae255a41b6 100644 --- a/sdk/storage/azure_storage_blob/assets.json +++ b/sdk/storage/azure_storage_blob/assets.json @@ -1,6 +1,6 @@ { "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "rust", - "Tag": "rust/azure_storage_blob_4dd8ebabce", + "Tag": "rust/azure_storage_blob_1e5e3b2c6c", "TagPrefix": "rust/azure_storage_blob" } diff --git a/sdk/storage/azure_storage_blob/perf/list_blob_test.rs b/sdk/storage/azure_storage_blob/perf/list_blob_test.rs index f9f2fca0f76..c459064292f 100644 --- a/sdk/storage/azure_storage_blob/perf/list_blob_test.rs +++ b/sdk/storage/azure_storage_blob/perf/list_blob_test.rs @@ -82,7 +82,7 @@ impl PerfTest for ListBlobTest { ), }; println!("Using endpoint: {}", endpoint); - let client = BlobContainerClient::new(&endpoint, container_name, credential, None)?; + let client = BlobContainerClient::new(&endpoint, &container_name, Some(credential), None)?; self.client.set(client).map_err(|_| { azure_core::Error::with_message(ErrorKind::Other, "Failed to set client") })?; @@ -94,7 +94,7 @@ impl PerfTest for ListBlobTest { // Create the blobs for the test. for i in 0..self.count { let blob_name = format!("blob-{}", i); - let blob_client = container_client.blob_client(blob_name); + let blob_client = container_client.blob_client(&blob_name); let body = vec![0u8; 1024 * 1024]; // 1 MB blob let body_bytes = Bytes::from(body); diff --git a/sdk/storage/azure_storage_blob/src/clients/append_blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/append_blob_client.rs index 47244cb2793..b7fb8159914 100644 --- a/sdk/storage/azure_storage_blob/src/clients/append_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/append_blob_client.rs @@ -10,39 +10,35 @@ use crate::{ AppendBlobClientSealResult, }, pipeline::StorageHeadersPolicy, - AppendBlobClientOptions, BlobClientOptions, + AppendBlobClientOptions, }; use azure_core::{ credentials::TokenCredential, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - NoFormat, RequestContent, Response, Url, + NoFormat, Pipeline, RequestContent, Response, Url, }, - Bytes, Result, + tracing, Bytes, Result, }; use std::sync::Arc; /// A client to interact with a specific Azure storage Append blob, although that blob may not yet exist. pub struct AppendBlobClient { - pub(crate) endpoint: Url, - pub(crate) client: GeneratedAppendBlobClient, + pub(super) client: GeneratedAppendBlobClient, } -impl AppendBlobClient { - /// Creates a new AppendBlobClient, using Entra ID authentication. +impl GeneratedAppendBlobClient { + /// Creates a new GeneratedAppendBlobClient from a blob URL. /// /// # Arguments /// - /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` - /// * `container_name` - The name of the container containing this Append blob. - /// * `blob_name` - The name of the Append blob to interact with. - /// * `credential` - An implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `blob_url` - The full URL of the Append blob, for example `https://myaccount.blob.core.windows.net/mycontainer/myblob`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. /// * `options` - Optional configuration for the client. - pub fn new( - endpoint: &str, - container_name: String, - blob_name: String, - credential: Arc, + #[tracing::new("Storage.Blob.AppendBlob")] + pub fn from_url( + blob_url: Url, + credential: Option>, options: Option, ) -> Result { let mut options = options.unwrap_or_default(); @@ -53,32 +49,92 @@ impl AppendBlobClient { .per_call_policies .push(storage_headers_policy); - let client = GeneratedAppendBlobClient::new( - endpoint, - credential, - container_name, - blob_name, - Some(options), - )?; + let per_retry_policies = if let Some(token_credential) = credential { + if !blob_url.scheme().starts_with("https") { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + format!("{blob_url} must use https"), + )); + } + let auth_policy: Arc = Arc::new(BearerTokenCredentialPolicy::new( + token_credential, + vec!["https://storage.azure.com/.default"], + )); + vec![auth_policy] + } else { + Vec::default() + }; + + let pipeline = Pipeline::new( + option_env!("CARGO_PKG_NAME"), + option_env!("CARGO_PKG_VERSION"), + options.client_options.clone(), + Vec::default(), + per_retry_policies, + None, + ); + Ok(Self { - endpoint: endpoint.parse()?, - client, + endpoint: blob_url, + version: options.version, + pipeline, }) } +} + +impl AppendBlobClient { + /// Creates a new AppendBlobClient, using Entra ID authentication. + /// + /// # Arguments + /// + /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` + /// * `container_name` - The name of the container containing this Append blob. + /// * `blob_name` - The name of the Append blob to interact with. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn new( + endpoint: &str, + container_name: &str, + blob_name: &str, + credential: Option>, + options: Option, + ) -> Result { + let mut url = Url::parse(endpoint)?; - /// Gets the endpoint of the Storage account this client is connected to. - pub fn endpoint(&self) -> &Url { - &self.endpoint + { + let mut path_segments = url.path_segments_mut().map_err(|_| { + azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + "Invalid endpoint URL: Failed to parse out path segments from provided endpoint URL.", + ) + })?; + path_segments.extend([container_name, blob_name]); + } + + let client = GeneratedAppendBlobClient::from_url(url, credential, options)?; + Ok(Self { client }) } - /// Gets the container name of the Storage account this client is connected to. - pub fn container_name(&self) -> &str { - &self.client.container_name + /// Creates a new AppendBlobClient from a blob URL. + /// + /// # Arguments + /// + /// * `blob_url` - The full URL of the Append blob, for example `https://myaccount.blob.core.windows.net/mycontainer/myblob`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn from_url( + blob_url: Url, + credential: Option>, + options: Option, + ) -> Result { + let client = GeneratedAppendBlobClient::from_url(blob_url, credential, options)?; + + Ok(Self { client }) } - /// Gets the blob name of the Storage account this client is connected to. - pub fn blob_name(&self) -> &str { - &self.client.blob_name + /// Gets the URL of the resource this client is configured for. + pub fn url(&self) -> &Url { + &self.client.endpoint } /// Creates a new Append blob. 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 7b09fab7aaa..8db31d1a8dc 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs @@ -2,7 +2,10 @@ // Licensed under the MIT License. use crate::{ + generated::clients::AppendBlobClient as GeneratedAppendBlobClient, generated::clients::BlobClient as GeneratedBlobClient, + generated::clients::BlockBlobClient as GeneratedBlockBlobClient, + generated::clients::PageBlobClient as GeneratedPageBlobClient, generated::models::{ BlobClientAcquireLeaseResult, BlobClientBreakLeaseResult, BlobClientChangeLeaseResult, BlobClientDownloadResult, BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, @@ -27,34 +30,31 @@ use azure_core::{ error::ErrorKind, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - AsyncResponse, JsonFormat, NoFormat, RequestContent, Response, StatusCode, Url, XmlFormat, + AsyncResponse, JsonFormat, NoFormat, Pipeline, RequestContent, Response, StatusCode, Url, + XmlFormat, }, - Bytes, Result, + tracing, Bytes, Result, }; use std::collections::HashMap; use std::sync::Arc; /// A client to interact with a specific Azure storage blob, although that blob may not yet exist. pub struct BlobClient { - pub(super) endpoint: Url, pub(super) client: GeneratedBlobClient, } -impl BlobClient { - /// Creates a new BlobClient, using Entra ID authentication. +impl GeneratedBlobClient { + /// Creates a new GeneratedBlobClient from a blob URL. /// /// # Arguments /// - /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` - /// * `container_name` - The name of the container containing this blob. - /// * `blob_name` - The name of the blob to interact with. - /// * `credential` - An implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `blob_url` - The full URL of the blob, for example `https://myaccount.blob.core.windows.net/mycontainer/myblob`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. /// * `options` - Optional configuration for the client. - pub fn new( - endpoint: &str, - container_name: String, - blob_name: String, - credential: Arc, + #[tracing::new("Storage.Blob.Blob")] + pub fn from_url( + blob_url: Url, + credential: Option>, options: Option, ) -> Result { let mut options = options.unwrap_or_default(); @@ -65,65 +65,127 @@ impl BlobClient { .per_call_policies .push(storage_headers_policy); - let client = GeneratedBlobClient::new( - endpoint, - credential, - container_name, - blob_name, - Some(options), - )?; + let per_retry_policies = if let Some(token_credential) = credential { + if !blob_url.scheme().starts_with("https") { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + format!("{blob_url} must use https"), + )); + } + let auth_policy: Arc = Arc::new(BearerTokenCredentialPolicy::new( + token_credential, + vec!["https://storage.azure.com/.default"], + )); + vec![auth_policy] + } else { + Vec::default() + }; + + let pipeline = Pipeline::new( + option_env!("CARGO_PKG_NAME"), + option_env!("CARGO_PKG_VERSION"), + options.client_options.clone(), + Vec::default(), + per_retry_policies, + None, + ); + Ok(Self { - endpoint: endpoint.parse()?, - client, + endpoint: blob_url, + version: options.version, + pipeline, }) } +} +impl BlobClient { + /// Creates a new BlobClient, using Entra ID authentication. + /// + /// # Arguments + /// + /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` + /// * `container_name` - The name of the container containing this blob. + /// * `blob_name` - The name of the blob to interact with. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn new( + endpoint: &str, + container_name: &str, + blob_name: &str, + credential: Option>, + options: Option, + ) -> Result { + let mut url = Url::parse(endpoint)?; - /// Returns a new instance of AppendBlobClient. + { + let mut path_segments = url.path_segments_mut().map_err(|_| { + azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + "Invalid endpoint URL: Failed to parse out path segments from provided endpoint URL.", + ) + })?; + path_segments.extend([container_name, blob_name]); + } + + let client = GeneratedBlobClient::from_url(url, credential, options)?; + Ok(Self { client }) + } + + /// Creates a new BlobClient from a blob URL. /// /// # Arguments /// + /// * `blob_url` - The full URL of the blob, for example `https://myaccount.blob.core.windows.net/mycontainer/myblob`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn from_url( + blob_url: Url, + credential: Option>, + options: Option, + ) -> Result { + let client = GeneratedBlobClient::from_url(blob_url, credential, options)?; + + Ok(Self { client }) + } + + /// Returns a new instance of AppendBlobClient. pub fn append_blob_client(&self) -> AppendBlobClient { AppendBlobClient { - endpoint: self.client.endpoint.clone(), - client: self.client.get_append_blob_client(), + client: GeneratedAppendBlobClient { + endpoint: self.client.endpoint.clone(), + pipeline: self.client.pipeline.clone(), + version: self.client.version.clone(), + tracer: self.client.tracer.clone(), + }, } } /// Returns a new instance of BlockBlobClient. - /// - /// # Arguments - /// pub fn block_blob_client(&self) -> BlockBlobClient { BlockBlobClient { - endpoint: self.client.endpoint.clone(), - client: self.client.get_block_blob_client(), + client: GeneratedBlockBlobClient { + endpoint: self.client.endpoint.clone(), + pipeline: self.client.pipeline.clone(), + version: self.client.version.clone(), + tracer: self.client.tracer.clone(), + }, } } /// Returns a new instance of PageBlobClient. - /// - /// # Arguments - /// pub fn page_blob_client(&self) -> PageBlobClient { PageBlobClient { - endpoint: self.client.endpoint.clone(), - client: self.client.get_page_blob_client(), + client: GeneratedPageBlobClient { + endpoint: self.client.endpoint.clone(), + pipeline: self.client.pipeline.clone(), + version: self.client.version.clone(), + tracer: self.client.tracer.clone(), + }, } } - /// Gets the endpoint of the Storage account this client is connected to. - pub fn endpoint(&self) -> &Url { - &self.endpoint - } - - /// Gets the container name of the Storage account this client is connected to. - pub fn container_name(&self) -> &str { - &self.client.container_name - } - - /// Gets the blob name of the Storage account this client is connected to. - pub fn blob_name(&self) -> &str { - &self.client.blob_name + /// Gets the URL of the resource this client is configured for. + pub fn url(&self) -> &Url { + &self.client.endpoint } /// Returns all user-defined metadata, standard HTTP properties, and system properties for the blob. @@ -183,8 +245,8 @@ impl BlobClient { options.if_none_match = Some(String::from("*")); } - self.client - .get_block_blob_client() + self.block_blob_client() + .client .upload(data, content_length, Some(options)) .await } 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 db6cca8956a..3c9004851da 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 @@ -2,22 +2,21 @@ // Licensed under the MIT License. use crate::{ + generated::clients::BlobClient as GeneratedBlobClient, generated::clients::BlobContainerClient as GeneratedBlobContainerClient, generated::models::{ - BlobContainerClientAcquireLeaseResult, BlobContainerClientBreakLeaseResult, - BlobContainerClientChangeLeaseResult, BlobContainerClientGetAccountInfoResult, - BlobContainerClientGetPropertiesResult, BlobContainerClientReleaseLeaseResult, - BlobContainerClientRenewLeaseResult, - }, - models::{ - BlobContainerClientAcquireLeaseOptions, BlobContainerClientBreakLeaseOptions, - BlobContainerClientChangeLeaseOptions, BlobContainerClientCreateOptions, - BlobContainerClientDeleteOptions, BlobContainerClientFindBlobsByTagsOptions, - BlobContainerClientGetAccountInfoOptions, BlobContainerClientGetPropertiesOptions, - BlobContainerClientListBlobFlatSegmentOptions, BlobContainerClientReleaseLeaseOptions, - BlobContainerClientRenewLeaseOptions, BlobContainerClientSetMetadataOptions, - FilterBlobSegment, ListBlobsFlatSegmentResponse, StorageErrorCode, + BlobContainerClientAcquireLeaseOptions, BlobContainerClientAcquireLeaseResult, + BlobContainerClientBreakLeaseOptions, BlobContainerClientBreakLeaseResult, + BlobContainerClientChangeLeaseOptions, BlobContainerClientChangeLeaseResult, + BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, + BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccountInfoOptions, + BlobContainerClientGetAccountInfoResult, BlobContainerClientGetPropertiesOptions, + BlobContainerClientGetPropertiesResult, BlobContainerClientListBlobFlatSegmentOptions, + BlobContainerClientReleaseLeaseOptions, BlobContainerClientReleaseLeaseResult, + BlobContainerClientRenewLeaseOptions, BlobContainerClientRenewLeaseResult, + BlobContainerClientSetMetadataOptions, }, + models::{FilterBlobSegment, ListBlobsFlatSegmentResponse, StorageErrorCode}, pipeline::StorageHeadersPolicy, BlobClient, BlobContainerClientOptions, }; @@ -26,31 +25,29 @@ use azure_core::{ error::ErrorKind, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - NoFormat, PageIterator, Pager, Response, StatusCode, Url, XmlFormat, + NoFormat, PageIterator, Pager, Pipeline, Response, StatusCode, Url, XmlFormat, }, - Result, + tracing, Result, }; use std::{collections::HashMap, sync::Arc}; -/// A client to interact with a specified Azure storage container. +/// A client to interact with a specified Azure storage container, although that container may not yet exist. pub struct BlobContainerClient { - pub(super) endpoint: Url, pub(super) client: GeneratedBlobContainerClient, } -impl BlobContainerClient { - /// Creates a new BlobContainerClient, using Entra ID authentication. +impl GeneratedBlobContainerClient { + /// Creates a new GeneratedBlobContainerClient from a container URL. /// /// # Arguments /// - /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` - /// * `container_name` - The name of the container. - /// * `credential` - An implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `container_url` - The full URL of the container, for example `https://myaccount.blob.core.windows.net/mycontainer`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. /// * `options` - Optional configuration for the client. - pub fn new( - endpoint: &str, - container_name: String, - credential: Arc, + #[tracing::new("Storage.Blob.Container")] + pub fn from_url( + container_url: Url, + credential: Option>, options: Option, ) -> Result { let mut options = options.unwrap_or_default(); @@ -61,39 +58,113 @@ impl BlobContainerClient { .per_call_policies .push(storage_headers_policy); - let client = GeneratedBlobContainerClient::new( - endpoint, - credential.clone(), - container_name.clone(), - Some(options), - )?; + let per_retry_policies = if let Some(token_credential) = credential { + if !container_url.scheme().starts_with("https") { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + format!("{container_url} must use https"), + )); + } + let auth_policy: Arc = Arc::new(BearerTokenCredentialPolicy::new( + token_credential, + vec!["https://storage.azure.com/.default"], + )); + vec![auth_policy] + } else { + Vec::default() + }; + + let pipeline = Pipeline::new( + option_env!("CARGO_PKG_NAME"), + option_env!("CARGO_PKG_VERSION"), + options.client_options.clone(), + Vec::default(), + per_retry_policies, + None, + ); Ok(Self { - endpoint: endpoint.parse()?, - client, + endpoint: container_url, + version: options.version, + pipeline, }) } +} - /// Returns a new instance of BlobClient. +impl BlobContainerClient { + /// Creates a new BlobContainerClient, using Entra ID authentication. /// /// # Arguments /// - /// * `blob_name` - The name of the blob. - pub fn blob_client(&self, blob_name: String) -> BlobClient { - BlobClient { - endpoint: self.client.endpoint.clone(), - client: self.client.get_blob_client(blob_name), + /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` + /// * `container_name` - The name of the container. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn new( + endpoint: &str, + container_name: &str, + credential: Option>, + options: Option, + ) -> Result { + let mut url = Url::parse(endpoint)?; + + { + let mut path_segments = url.path_segments_mut().map_err(|_| { + azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + "Invalid endpoint URL: Failed to parse out path segments from provided endpoint URL.", + ) + })?; + path_segments.extend([container_name]); } + + let client = GeneratedBlobContainerClient::from_url(url, credential, options)?; + Ok(Self { client }) } - /// Gets the endpoint of the Storage account this client is connected to. - pub fn endpoint(&self) -> &Url { - &self.endpoint + /// Creates a new BlobContainerClient from a container URL. + /// + /// # Arguments + /// + /// * `container_url` - The full URL of the container, for example `https://myaccount.blob.core.windows.net/mycontainer`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn from_url( + container_url: Url, + credential: Option>, + options: Option, + ) -> Result { + let client = GeneratedBlobContainerClient::from_url(container_url, credential, options)?; + + Ok(Self { client }) + } + + /// Returns a new instance of BlobClient. + /// + /// # Arguments + /// + /// * `blob_name` - The name of the blob. + pub fn blob_client(&self, blob_name: &str) -> BlobClient { + let mut blob_url = self.url().clone(); + blob_url + .path_segments_mut() + // This should not fail as container URL has already been validated on client construction. + .expect("Invalid endpoint URL: Cannot append blob_name to the blob endpoint.") + .extend([blob_name]); + + let client = GeneratedBlobClient { + endpoint: blob_url, + pipeline: self.client.pipeline.clone(), + version: self.client.version.clone(), + tracer: self.client.tracer.clone(), + }; + + BlobClient { client } } - /// Gets the container name of the Storage account this client is connected to. - pub fn container_name(&self) -> &str { - &self.client.container_name + /// Gets the URL of the resource this client is configured for. + pub fn url(&self) -> &Url { + &self.client.endpoint } /// Creates a new container under the specified account. If the container with the same name already exists, the operation fails. 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 08648d7ca54..0332db26bda 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 @@ -2,6 +2,7 @@ // Licensed under the MIT License. use crate::{ + generated::clients::BlobContainerClient as GeneratedBlobContainerClient, generated::clients::BlobServiceClient as GeneratedBlobServiceClient, generated::models::BlobServiceClientGetAccountInfoResult, models::{ @@ -17,29 +18,29 @@ use azure_core::{ credentials::TokenCredential, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - NoFormat, PageIterator, RequestContent, Response, Url, XmlFormat, + NoFormat, PageIterator, Pipeline, RequestContent, Response, Url, XmlFormat, }, - Result, + tracing, Result, }; use std::sync::Arc; /// A client to interact with an Azure storage account. pub struct BlobServiceClient { - pub(super) endpoint: Url, pub(super) client: GeneratedBlobServiceClient, } -impl BlobServiceClient { - /// Creates a new BlobServiceClient, using Entra ID authentication. +impl GeneratedBlobServiceClient { + /// Creates a new GeneratedBlobServiceClient from the URL of the Azure storage account. /// /// # Arguments /// - /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` - /// * `credential` - An implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `blob_service_url` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. /// * `options` - Optional configuration for the client. - pub fn new( - endpoint: &str, - credential: Arc, + #[tracing::new("Storage.Blob.Service")] + pub fn from_url( + blob_service_url: Url, + credential: Option>, options: Option, ) -> Result { let mut options = options.unwrap_or_default(); @@ -50,29 +51,84 @@ impl BlobServiceClient { .per_call_policies .push(storage_headers_policy); - let client = GeneratedBlobServiceClient::new(endpoint, credential.clone(), Some(options))?; + let per_retry_policies = if let Some(token_credential) = credential { + if !blob_service_url.scheme().starts_with("https") { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + format!("{blob_service_url} must use https"), + )); + } + let auth_policy: Arc = Arc::new(BearerTokenCredentialPolicy::new( + token_credential, + vec!["https://storage.azure.com/.default"], + )); + vec![auth_policy] + } else { + Vec::default() + }; + + let pipeline = Pipeline::new( + option_env!("CARGO_PKG_NAME"), + option_env!("CARGO_PKG_VERSION"), + options.client_options.clone(), + Vec::default(), + per_retry_policies, + None, + ); Ok(Self { - endpoint: endpoint.parse()?, - client, + endpoint: blob_service_url, + version: options.version, + pipeline, }) } +} + +impl BlobServiceClient { + /// Creates a new BlobServiceClient, using Entra ID authentication. + /// + /// # Arguments + /// + /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn new( + endpoint: &str, + credential: Option>, + options: Option, + ) -> Result { + let url = Url::parse(endpoint)?; + + let client = GeneratedBlobServiceClient::from_url(url, credential, options)?; + Ok(Self { client }) + } /// Returns a new instance of BlobContainerClient. /// /// # Arguments /// /// * `container_name` - The name of the container. - pub fn blob_container_client(&self, container_name: String) -> BlobContainerClient { - BlobContainerClient { - endpoint: self.client.endpoint.clone(), - client: self.client.get_blob_container_client(container_name), - } + pub fn blob_container_client(&self, container_name: &str) -> BlobContainerClient { + let mut container_url = self.url().clone(); + container_url + .path_segments_mut() + // This should not fail as service URL has already been validated on client construction. + .expect("Cannot be a base URL.") + .push(container_name); + + let client = GeneratedBlobContainerClient { + endpoint: container_url, + pipeline: self.client.pipeline.clone(), + version: self.client.version.clone(), + tracer: self.client.tracer.clone(), + }; + + BlobContainerClient { client } } - /// Gets the endpoint of the Storage account this client is connected to. - pub fn endpoint(&self) -> &Url { - &self.endpoint + /// Gets the URL of the resource this client is configured for. + pub fn url(&self) -> &Url { + &self.client.endpoint } /// Gets the properties of a Storage account's Blob service, including Azure Storage Analytics. 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 5e51224bd66..44667160876 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 @@ -16,39 +16,35 @@ use crate::{ BlockBlobClientUploadOptions, BlockList, BlockListType, BlockLookupList, }, pipeline::StorageHeadersPolicy, - BlobClientOptions, BlockBlobClientOptions, + BlockBlobClientOptions, }; use azure_core::{ credentials::TokenCredential, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - NoFormat, RequestContent, Response, Url, XmlFormat, + NoFormat, Pipeline, RequestContent, Response, Url, XmlFormat, }, - Bytes, Result, + tracing, Bytes, Result, }; use std::sync::Arc; /// A client to interact with a specific Azure storage Block blob, although that blob may not yet exist. pub struct BlockBlobClient { - pub(crate) endpoint: Url, - pub(crate) client: GeneratedBlockBlobClient, + pub(super) client: GeneratedBlockBlobClient, } -impl BlockBlobClient { - /// Creates a new BlockBlobClient, using Entra ID authentication. +impl GeneratedBlockBlobClient { + /// Creates a new GeneratedBlockBlobClient from a block blob URL. /// /// # Arguments /// - /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` - /// * `container_name` - The name of the container containing this Block blob. - /// * `blob_name` - The name of the Block blob to interact with. - /// * `credential` - An implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `blob_url` - The full URL of the block blob, for example `https://myaccount.blob.core.windows.net/mycontainer/myblob`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. /// * `options` - Optional configuration for the client. - pub fn new( - endpoint: &str, - container_name: String, - blob_name: String, - credential: Arc, + #[tracing::new("Storage.Blob.BlockBlob")] + pub fn from_url( + blob_url: Url, + credential: Option>, options: Option, ) -> Result { let mut options = options.unwrap_or_default(); @@ -59,32 +55,92 @@ impl BlockBlobClient { .per_call_policies .push(storage_headers_policy); - let client = GeneratedBlockBlobClient::new( - endpoint, - credential, - container_name, - blob_name, - Some(options), - )?; + let per_retry_policies = if let Some(token_credential) = credential { + if !blob_url.scheme().starts_with("https") { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + format!("{blob_url} must use https"), + )); + } + let auth_policy: Arc = Arc::new(BearerTokenCredentialPolicy::new( + token_credential, + vec!["https://storage.azure.com/.default"], + )); + vec![auth_policy] + } else { + Vec::default() + }; + + let pipeline = Pipeline::new( + option_env!("CARGO_PKG_NAME"), + option_env!("CARGO_PKG_VERSION"), + options.client_options.clone(), + Vec::default(), + per_retry_policies, + None, + ); + Ok(Self { - endpoint: endpoint.parse()?, - client, + endpoint: blob_url, + version: options.version, + pipeline, }) } +} + +impl BlockBlobClient { + /// Creates a new BlockBlobClient, using Entra ID authentication. + /// + /// # Arguments + /// + /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` + /// * `container_name` - The name of the container containing this Block blob. + /// * `blob_name` - The name of the Block blob to interact with. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn new( + endpoint: &str, + container_name: &str, + blob_name: &str, + credential: Option>, + options: Option, + ) -> Result { + let mut url = Url::parse(endpoint)?; - /// Gets the endpoint of the Storage account this client is connected to. - pub fn endpoint(&self) -> &Url { - &self.endpoint + { + let mut path_segments = url.path_segments_mut().map_err(|_| { + azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + "Invalid endpoint URL: Failed to parse out path segments from provided endpoint URL.", + ) + })?; + path_segments.extend([container_name, blob_name]); + } + + let client = GeneratedBlockBlobClient::from_url(url, credential, options)?; + Ok(Self { client }) } - /// Gets the container name of the Storage account this client is connected to. - pub fn container_name(&self) -> &str { - &self.client.container_name + /// Creates a new BlockBlobClient from a Block blob URL. + /// + /// # Arguments + /// + /// * `blob_url` - The full URL of the Block blob, for example `https://myaccount.blob.core.windows.net/mycontainer/myblob`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn from_url( + blob_url: Url, + credential: Option>, + options: Option, + ) -> Result { + let client = GeneratedBlockBlobClient::from_url(blob_url, credential, options)?; + + Ok(Self { client }) } - /// Gets the blob name of the Storage account this client is connected to. - pub fn blob_name(&self) -> &str { - &self.client.blob_name + /// Gets the URL of the resource this client is configured for. + pub fn url(&self) -> &Url { + &self.client.endpoint } /// Writes to a blob based on blocks specified by the list of IDs and content that make up the blob. diff --git a/sdk/storage/azure_storage_blob/src/clients/page_blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/page_blob_client.rs index 3784bfe4caf..d4e7991b4a2 100644 --- a/sdk/storage/azure_storage_blob/src/clients/page_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/page_blob_client.rs @@ -13,39 +13,35 @@ use crate::{ PageBlobClientUploadPagesResult, PageList, SequenceNumberActionType, }, pipeline::StorageHeadersPolicy, - BlobClientOptions, PageBlobClientOptions, + PageBlobClientOptions, }; use azure_core::{ credentials::TokenCredential, http::{ policies::{BearerTokenCredentialPolicy, Policy}, - NoFormat, RequestContent, Response, Url, XmlFormat, + NoFormat, Pipeline, RequestContent, Response, Url, XmlFormat, }, - Bytes, Result, + tracing, Bytes, Result, }; use std::sync::Arc; /// A client to interact with a specific Azure storage Page blob, although that blob may not yet exist. pub struct PageBlobClient { - pub(crate) endpoint: Url, - pub(crate) client: GeneratedPageBlobClient, + pub(super) client: GeneratedPageBlobClient, } -impl PageBlobClient { - /// Creates a new PageBlobClient, using Entra ID authentication. +impl GeneratedPageBlobClient { + /// Creates a new GeneratedPageBlobClient from a blob URL. /// /// # Arguments /// - /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` - /// * `container_name` - The name of the container containing this Page blob. - /// * `blob_name` - The name of the Page blob to interact with. - /// * `credential` - An implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `blob_url` - The full URL of the Page blob, for example `https://myaccount.blob.core.windows.net/mycontainer/myblob`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. /// * `options` - Optional configuration for the client. - pub fn new( - endpoint: &str, - container_name: String, - blob_name: String, - credential: Arc, + #[tracing::new("Storage.Blob.PageBlob")] + pub fn from_url( + blob_url: Url, + credential: Option>, options: Option, ) -> Result { let mut options = options.unwrap_or_default(); @@ -56,32 +52,92 @@ impl PageBlobClient { .per_call_policies .push(storage_headers_policy); - let client = GeneratedPageBlobClient::new( - endpoint, - credential, - container_name, - blob_name, - Some(options), - )?; + let per_retry_policies = if let Some(token_credential) = credential { + if !blob_url.scheme().starts_with("https") { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + format!("{blob_url} must use https"), + )); + } + let auth_policy: Arc = Arc::new(BearerTokenCredentialPolicy::new( + token_credential, + vec!["https://storage.azure.com/.default"], + )); + vec![auth_policy] + } else { + Vec::default() + }; + + let pipeline = Pipeline::new( + option_env!("CARGO_PKG_NAME"), + option_env!("CARGO_PKG_VERSION"), + options.client_options.clone(), + Vec::default(), + per_retry_policies, + None, + ); + Ok(Self { - endpoint: endpoint.parse()?, - client, + endpoint: blob_url, + version: options.version, + pipeline, }) } +} + +impl PageBlobClient { + /// Creates a new PageBlobClient, using Entra ID authentication. + /// + /// # Arguments + /// + /// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/` + /// * `container_name` - The name of the container containing this Page blob. + /// * `blob_name` - The name of the Page blob to interact with. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn new( + endpoint: &str, + container_name: &str, + blob_name: &str, + credential: Option>, + options: Option, + ) -> Result { + let mut url = Url::parse(endpoint)?; - /// Gets the endpoint of the Storage account this client is connected to. - pub fn endpoint(&self) -> &Url { - &self.endpoint + { + let mut path_segments = url.path_segments_mut().map_err(|_| { + azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + "Invalid endpoint URL: Failed to parse out path segments from provided endpoint URL.", + ) + })?; + path_segments.extend([container_name, blob_name]); + } + + let client = GeneratedPageBlobClient::from_url(url, credential, options)?; + Ok(Self { client }) } - /// Gets the container name of the Storage account this client is connected to. - pub fn container_name(&self) -> &str { - &self.client.container_name + /// Creates a new PageBlobClient from a blob URL. + /// + /// # Arguments + /// + /// * `blob_url` - The full URL of the Page blob, for example `https://myaccount.blob.core.windows.net/mycontainer/myblob`. + /// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating. + /// * `options` - Optional configuration for the client. + pub fn from_url( + blob_url: Url, + credential: Option>, + options: Option, + ) -> Result { + let client = GeneratedPageBlobClient::from_url(blob_url, credential, options)?; + + Ok(Self { client }) } - /// Gets the blob name of the Storage account this client is connected to. - pub fn blob_name(&self) -> &str { - &self.client.blob_name + /// Gets the URL of the resource this client is configured for. + pub fn url(&self) -> &Url { + &self.client.endpoint } /// Creates a new Page blob. 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 3261f4c9695..4de80a0bdfc 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 @@ -26,8 +26,6 @@ use std::sync::Arc; #[tracing::client] pub struct AppendBlobClient { - pub(crate) blob_name: String, - pub(crate) container_name: String, pub(crate) endpoint: Url, pub(crate) pipeline: Pipeline, pub(crate) version: String, @@ -50,15 +48,11 @@ impl AppendBlobClient { /// * `endpoint` - Service host /// * `credential` - An implementation of [`TokenCredential`](azure_core::credentials::TokenCredential) that can provide an /// Entra ID token to use when authenticating. - /// * `container_name` - The name of the container. - /// * `blob_name` - The name of the blob. /// * `options` - Optional configuration for the client. - #[tracing::new("Storage.Blob.Container.Blob.AppendBlob")] + #[tracing::new("Storage.Blob.AppendBlob")] pub fn new( endpoint: &str, credential: Arc, - container_name: String, - blob_name: String, options: Option, ) -> Result { let options = options.unwrap_or_default(); @@ -74,8 +68,6 @@ impl AppendBlobClient { vec!["https://storage.azure.com/.default"], )); Ok(Self { - blob_name, - container_name, endpoint, version: options.version, pipeline: Pipeline::new( @@ -138,7 +130,7 @@ impl AppendBlobClient { /// * [`is_server_encrypted`()](crate::generated::models::AppendBlobClientAppendBlockResultHeaders::is_server_encrypted) - x-ms-request-server-encrypted /// /// [`AppendBlobClientAppendBlockResultHeaders`]: crate::generated::models::AppendBlobClientAppendBlockResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.AppendBlob.appendBlock")] + #[tracing::function("Storage.Blob.AppendBlob.appendBlock")] pub async fn append_block( &self, body: RequestContent, @@ -148,10 +140,6 @@ impl AppendBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "appendblock"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -280,7 +268,7 @@ impl AppendBlobClient { /// * [`is_server_encrypted`()](crate::generated::models::AppendBlobClientAppendBlockFromUrlResultHeaders::is_server_encrypted) - x-ms-request-server-encrypted /// /// [`AppendBlobClientAppendBlockFromUrlResultHeaders`]: crate::generated::models::AppendBlobClientAppendBlockFromUrlResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.AppendBlob.appendBlockFromUrl")] + #[tracing::function("Storage.Blob.AppendBlob.appendBlockFromUrl")] pub async fn append_block_from_url( &self, source_url: String, @@ -290,10 +278,6 @@ impl AppendBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "appendblock") .append_key_only("fromUrl"); @@ -440,7 +424,7 @@ impl AppendBlobClient { /// * [`version_id`()](crate::generated::models::AppendBlobClientCreateResultHeaders::version_id) - x-ms-version-id /// /// [`AppendBlobClientCreateResultHeaders`]: crate::generated::models::AppendBlobClientCreateResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.AppendBlob.create")] + #[tracing::function("Storage.Blob.AppendBlob.create")] pub async fn create( &self, options: Option>, @@ -448,10 +432,6 @@ impl AppendBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; if let Some(timeout) = options.timeout { url.query_pairs_mut() .append_pair("timeout", &timeout.to_string()); @@ -590,7 +570,7 @@ impl AppendBlobClient { /// * [`is_sealed`()](crate::generated::models::AppendBlobClientSealResultHeaders::is_sealed) - x-ms-blob-sealed /// /// [`AppendBlobClientSealResultHeaders`]: crate::generated::models::AppendBlobClientSealResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.AppendBlob.seal")] + #[tracing::function("Storage.Blob.AppendBlob.seal")] pub async fn seal( &self, options: Option>, @@ -598,10 +578,6 @@ impl AppendBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "seal"); if let Some(timeout) = options.timeout { url.query_pairs_mut() 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 9e0b8a25861..f9d96a715f4 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 @@ -3,26 +3,22 @@ // 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 crate::generated::{ - clients::{AppendBlobClient, BlockBlobClient, PageBlobClient}, - models::{ - AccessTier, BlobClientAbortCopyFromUrlOptions, BlobClientAbortCopyFromUrlResult, - BlobClientAcquireLeaseOptions, BlobClientAcquireLeaseResult, BlobClientBreakLeaseOptions, - BlobClientBreakLeaseResult, BlobClientChangeLeaseOptions, BlobClientChangeLeaseResult, - BlobClientCopyFromUrlOptions, BlobClientCopyFromUrlResult, BlobClientCreateSnapshotOptions, - BlobClientCreateSnapshotResult, BlobClientDeleteImmutabilityPolicyOptions, - BlobClientDeleteImmutabilityPolicyResult, BlobClientDeleteOptions, - BlobClientDownloadOptions, BlobClientDownloadResult, BlobClientGetAccountInfoOptions, - BlobClientGetAccountInfoResult, BlobClientGetPropertiesOptions, - BlobClientGetPropertiesResult, BlobClientGetTagsOptions, BlobClientReleaseLeaseOptions, - BlobClientReleaseLeaseResult, BlobClientRenewLeaseOptions, BlobClientRenewLeaseResult, - BlobClientSetExpiryOptions, BlobClientSetExpiryResult, - BlobClientSetImmutabilityPolicyOptions, BlobClientSetImmutabilityPolicyResult, - BlobClientSetLegalHoldOptions, BlobClientSetLegalHoldResult, BlobClientSetMetadataOptions, - BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, BlobClientSetTierOptions, - BlobClientStartCopyFromUrlOptions, BlobClientStartCopyFromUrlResult, - BlobClientUndeleteOptions, BlobClientUndeleteResult, BlobExpiryOptions, BlobTags, - }, +use crate::generated::models::{ + AccessTier, BlobClientAbortCopyFromUrlOptions, BlobClientAbortCopyFromUrlResult, + BlobClientAcquireLeaseOptions, BlobClientAcquireLeaseResult, BlobClientBreakLeaseOptions, + BlobClientBreakLeaseResult, BlobClientChangeLeaseOptions, BlobClientChangeLeaseResult, + BlobClientCopyFromUrlOptions, BlobClientCopyFromUrlResult, BlobClientCreateSnapshotOptions, + BlobClientCreateSnapshotResult, BlobClientDeleteImmutabilityPolicyOptions, + BlobClientDeleteImmutabilityPolicyResult, BlobClientDeleteOptions, BlobClientDownloadOptions, + BlobClientDownloadResult, BlobClientGetAccountInfoOptions, BlobClientGetAccountInfoResult, + BlobClientGetPropertiesOptions, BlobClientGetPropertiesResult, BlobClientGetTagsOptions, + BlobClientReleaseLeaseOptions, BlobClientReleaseLeaseResult, BlobClientRenewLeaseOptions, + BlobClientRenewLeaseResult, BlobClientSetExpiryOptions, BlobClientSetExpiryResult, + BlobClientSetImmutabilityPolicyOptions, BlobClientSetImmutabilityPolicyResult, + BlobClientSetLegalHoldOptions, BlobClientSetLegalHoldResult, BlobClientSetMetadataOptions, + BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, BlobClientSetTierOptions, + BlobClientStartCopyFromUrlOptions, BlobClientStartCopyFromUrlResult, BlobClientUndeleteOptions, + BlobClientUndeleteResult, BlobExpiryOptions, BlobTags, }; use azure_core::{ base64::encode, @@ -41,8 +37,6 @@ use std::{collections::HashMap, sync::Arc}; #[tracing::client] pub struct BlobClient { - pub(crate) blob_name: String, - pub(crate) container_name: String, pub(crate) endpoint: Url, pub(crate) pipeline: Pipeline, pub(crate) version: String, @@ -65,15 +59,11 @@ impl BlobClient { /// * `endpoint` - Service host /// * `credential` - An implementation of [`TokenCredential`](azure_core::credentials::TokenCredential) that can provide an /// Entra ID token to use when authenticating. - /// * `container_name` - The name of the container. - /// * `blob_name` - The name of the blob. /// * `options` - Optional configuration for the client. - #[tracing::new("Storage.Blob.Container.Blob")] + #[tracing::new("Storage.Blob.Blob")] pub fn new( endpoint: &str, credential: Arc, - container_name: String, - blob_name: String, options: Option, ) -> Result { let options = options.unwrap_or_default(); @@ -89,8 +79,6 @@ impl BlobClient { vec!["https://storage.azure.com/.default"], )); Ok(Self { - blob_name, - container_name, endpoint, version: options.version, pipeline: Pipeline::new( @@ -139,7 +127,7 @@ impl BlobClient { /// * [`date`()](crate::generated::models::BlobClientAbortCopyFromUrlResultHeaders::date) - Date /// /// [`BlobClientAbortCopyFromUrlResultHeaders`]: crate::generated::models::BlobClientAbortCopyFromUrlResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.abortCopyFromUrl")] + #[tracing::function("Storage.Blob.Blob.abortCopyFromUrl")] pub async fn abort_copy_from_url( &self, copy_id: &str, @@ -148,10 +136,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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") .append_key_only("copyid"); @@ -225,7 +209,7 @@ impl BlobClient { /// * [`lease_id`()](crate::generated::models::BlobClientAcquireLeaseResultHeaders::lease_id) - x-ms-lease-id /// /// [`BlobClientAcquireLeaseResultHeaders`]: crate::generated::models::BlobClientAcquireLeaseResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.acquireLease")] + #[tracing::function("Storage.Blob.Blob.acquireLease")] pub async fn acquire_lease( &self, duration: i32, @@ -234,10 +218,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("acquire") .append_pair("comp", "lease"); @@ -323,7 +303,7 @@ impl BlobClient { /// * [`lease_time`()](crate::generated::models::BlobClientBreakLeaseResultHeaders::lease_time) - x-ms-lease-time /// /// [`BlobClientBreakLeaseResultHeaders`]: crate::generated::models::BlobClientBreakLeaseResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.breakLease")] + #[tracing::function("Storage.Blob.Blob.breakLease")] pub async fn break_lease( &self, options: Option>, @@ -331,10 +311,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("break") .append_pair("comp", "lease"); @@ -422,7 +398,7 @@ impl BlobClient { /// * [`lease_id`()](crate::generated::models::BlobClientChangeLeaseResultHeaders::lease_id) - x-ms-lease-id /// /// [`BlobClientChangeLeaseResultHeaders`]: crate::generated::models::BlobClientChangeLeaseResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.changeLease")] + #[tracing::function("Storage.Blob.Blob.changeLease")] pub async fn change_lease( &self, lease_id: String, @@ -432,10 +408,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("change") .append_pair("comp", "lease"); @@ -528,7 +500,7 @@ impl BlobClient { /// * [`version_id`()](crate::generated::models::BlobClientCopyFromUrlResultHeaders::version_id) - x-ms-version-id /// /// [`BlobClientCopyFromUrlResultHeaders`]: crate::generated::models::BlobClientCopyFromUrlResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.copyFromUrl")] + #[tracing::function("Storage.Blob.Blob.copyFromUrl")] pub async fn copy_from_url( &self, copy_source: String, @@ -537,10 +509,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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") .append_key_only("sync"); @@ -688,7 +656,7 @@ impl BlobClient { /// * [`version_id`()](crate::generated::models::BlobClientCreateSnapshotResultHeaders::version_id) - x-ms-version-id /// /// [`BlobClientCreateSnapshotResultHeaders`]: crate::generated::models::BlobClientCreateSnapshotResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.createSnapshot")] + #[tracing::function("Storage.Blob.Blob.createSnapshot")] pub async fn create_snapshot( &self, options: Option>, @@ -696,10 +664,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "snapshot"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -778,7 +742,7 @@ impl BlobClient { /// # Arguments /// /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.Container.Blob.delete")] + #[tracing::function("Storage.Blob.Blob.delete")] pub async fn delete( &self, options: Option>, @@ -786,10 +750,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; if let Some(blob_delete_type) = options.blob_delete_type { url.query_pairs_mut() .append_pair("deletetype", blob_delete_type.as_ref()); @@ -875,7 +835,7 @@ impl BlobClient { /// * [`date`()](crate::generated::models::BlobClientDeleteImmutabilityPolicyResultHeaders::date) - Date /// /// [`BlobClientDeleteImmutabilityPolicyResultHeaders`]: crate::generated::models::BlobClientDeleteImmutabilityPolicyResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.deleteImmutabilityPolicy")] + #[tracing::function("Storage.Blob.Blob.deleteImmutabilityPolicy")] pub async fn delete_immutability_policy( &self, options: Option>, @@ -883,10 +843,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "immutabilityPolicies"); if let Some(snapshot) = options.snapshot { @@ -993,7 +949,7 @@ impl BlobClient { /// * [`version_id`()](crate::generated::models::BlobClientDownloadResultHeaders::version_id) - x-ms-version-id /// /// [`BlobClientDownloadResultHeaders`]: crate::generated::models::BlobClientDownloadResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.download")] + #[tracing::function("Storage.Blob.Blob.download")] pub async fn download( &self, options: Option>, @@ -1001,10 +957,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; if let Some(snapshot) = options.snapshot { url.query_pairs_mut().append_pair("snapshot", &snapshot); } @@ -1102,26 +1054,27 @@ impl BlobClient { /// async fn example() -> Result<()> { /// let response: Response = unimplemented!(); /// // Access response headers + /// if let Some(date) = response.date()? { + /// println!("Date: {:?}", date); + /// } /// if let Some(account_kind) = response.account_kind()? { /// println!("x-ms-account-kind: {:?}", account_kind); /// } /// if let Some(is_hierarchical_namespace_enabled) = response.is_hierarchical_namespace_enabled()? { /// println!("x-ms-is-hns-enabled: {:?}", is_hierarchical_namespace_enabled); /// } - /// if let Some(sku_name) = response.sku_name()? { - /// println!("x-ms-sku-name: {:?}", sku_name); - /// } /// Ok(()) /// } /// ``` /// /// ### Available headers + /// * [`date`()](crate::generated::models::BlobClientGetAccountInfoResultHeaders::date) - Date /// * [`account_kind`()](crate::generated::models::BlobClientGetAccountInfoResultHeaders::account_kind) - x-ms-account-kind /// * [`is_hierarchical_namespace_enabled`()](crate::generated::models::BlobClientGetAccountInfoResultHeaders::is_hierarchical_namespace_enabled) - x-ms-is-hns-enabled /// * [`sku_name`()](crate::generated::models::BlobClientGetAccountInfoResultHeaders::sku_name) - x-ms-sku-name /// /// [`BlobClientGetAccountInfoResultHeaders`]: crate::generated::models::BlobClientGetAccountInfoResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.getAccountInfo")] + #[tracing::function("Storage.Blob.Blob.getAccountInfo")] pub async fn get_account_info( &self, options: Option>, @@ -1129,10 +1082,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("blob") .append_pair("comp", "properties") @@ -1163,42 +1112,6 @@ impl BlobClient { Ok(rsp.into()) } - /// Returns a new instance of AppendBlobClient. - #[tracing::subclient] - pub fn get_append_blob_client(&self) -> AppendBlobClient { - AppendBlobClient { - blob_name: self.blob_name.clone(), - container_name: self.container_name.clone(), - endpoint: self.endpoint.clone(), - pipeline: self.pipeline.clone(), - version: self.version.clone(), - } - } - - /// Returns a new instance of BlockBlobClient. - #[tracing::subclient] - pub fn get_block_blob_client(&self) -> BlockBlobClient { - BlockBlobClient { - blob_name: self.blob_name.clone(), - container_name: self.container_name.clone(), - endpoint: self.endpoint.clone(), - pipeline: self.pipeline.clone(), - version: self.version.clone(), - } - } - - /// Returns a new instance of PageBlobClient. - #[tracing::subclient] - pub fn get_page_blob_client(&self) -> PageBlobClient { - PageBlobClient { - blob_name: self.blob_name.clone(), - container_name: self.container_name.clone(), - endpoint: self.endpoint.clone(), - pipeline: self.pipeline.clone(), - version: self.version.clone(), - } - } - /// The Get Properties operation returns all user-defined metadata, standard HTTP properties, and system properties for the /// blob. It does not return the content of the blob. /// @@ -1276,7 +1189,7 @@ impl BlobClient { /// * [`version_id`()](crate::generated::models::BlobClientGetPropertiesResultHeaders::version_id) - x-ms-version-id /// /// [`BlobClientGetPropertiesResultHeaders`]: crate::generated::models::BlobClientGetPropertiesResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.getProperties")] + #[tracing::function("Storage.Blob.Blob.getProperties")] pub async fn get_properties( &self, options: Option>, @@ -1284,10 +1197,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; if let Some(snapshot) = options.snapshot { url.query_pairs_mut().append_pair("snapshot", &snapshot); } @@ -1377,7 +1286,7 @@ impl BlobClient { /// * [`date`()](crate::generated::models::BlobTagsHeaders::date) - Date /// /// [`BlobTagsHeaders`]: crate::generated::models::BlobTagsHeaders - #[tracing::function("Storage.Blob.Container.Blob.getTags")] + #[tracing::function("Storage.Blob.Blob.getTags")] pub async fn get_tags( &self, options: Option>, @@ -1385,10 +1294,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "tags"); if let Some(snapshot) = options.snapshot { url.query_pairs_mut().append_pair("snapshot", &snapshot); @@ -1464,7 +1369,7 @@ impl BlobClient { /// * [`etag`()](crate::generated::models::BlobClientReleaseLeaseResultHeaders::etag) - etag /// /// [`BlobClientReleaseLeaseResultHeaders`]: crate::generated::models::BlobClientReleaseLeaseResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.releaseLease")] + #[tracing::function("Storage.Blob.Blob.releaseLease")] pub async fn release_lease( &self, lease_id: String, @@ -1473,10 +1378,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "lease") .append_key_only("release"); @@ -1561,7 +1462,7 @@ impl BlobClient { /// * [`lease_id`()](crate::generated::models::BlobClientRenewLeaseResultHeaders::lease_id) - x-ms-lease-id /// /// [`BlobClientRenewLeaseResultHeaders`]: crate::generated::models::BlobClientRenewLeaseResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.renewLease")] + #[tracing::function("Storage.Blob.Blob.renewLease")] pub async fn renew_lease( &self, lease_id: String, @@ -1570,10 +1471,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "lease") .append_key_only("renew"); @@ -1657,7 +1554,7 @@ impl BlobClient { /// * [`etag`()](crate::generated::models::BlobClientSetExpiryResultHeaders::etag) - etag /// /// [`BlobClientSetExpiryResultHeaders`]: crate::generated::models::BlobClientSetExpiryResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.setExpiry")] + #[tracing::function("Storage.Blob.Blob.setExpiry")] pub async fn set_expiry( &self, expiry_options: BlobExpiryOptions, @@ -1666,10 +1563,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "expiry"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -1737,7 +1630,7 @@ impl BlobClient { /// * [`immutability_policy_expires_on`()](crate::generated::models::BlobClientSetImmutabilityPolicyResultHeaders::immutability_policy_expires_on) - x-ms-immutability-policy-until-date /// /// [`BlobClientSetImmutabilityPolicyResultHeaders`]: crate::generated::models::BlobClientSetImmutabilityPolicyResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.setImmutabilityPolicy")] + #[tracing::function("Storage.Blob.Blob.setImmutabilityPolicy")] pub async fn set_immutability_policy( &self, options: Option>, @@ -1745,10 +1638,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "immutabilityPolicies"); if let Some(snapshot) = options.snapshot { @@ -1831,7 +1720,7 @@ impl BlobClient { /// * [`legal_hold`()](crate::generated::models::BlobClientSetLegalHoldResultHeaders::legal_hold) - x-ms-legal-hold /// /// [`BlobClientSetLegalHoldResultHeaders`]: crate::generated::models::BlobClientSetLegalHoldResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.setLegalHold")] + #[tracing::function("Storage.Blob.Blob.setLegalHold")] pub async fn set_legal_hold( &self, legal_hold: bool, @@ -1840,10 +1729,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "legalhold"); if let Some(snapshot) = options.snapshot { url.query_pairs_mut().append_pair("snapshot", &snapshot); @@ -1884,7 +1769,7 @@ impl BlobClient { /// /// * `metadata` - The metadata headers. /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.Container.Blob.setMetadata")] + #[tracing::function("Storage.Blob.Blob.setMetadata")] pub async fn set_metadata( &self, metadata: HashMap, @@ -1893,10 +1778,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "metadata"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -1965,7 +1846,7 @@ impl BlobClient { /// # Arguments /// /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.Container.Blob.setProperties")] + #[tracing::function("Storage.Blob.Blob.setProperties")] pub async fn set_properties( &self, options: Option>, @@ -1973,10 +1854,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("SetHTTPHeaders") .append_pair("comp", "properties"); @@ -2048,7 +1925,7 @@ impl BlobClient { /// /// * `tags` - The blob tags. /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.Container.Blob.setTags")] + #[tracing::function("Storage.Blob.Blob.setTags")] pub async fn set_tags( &self, tags: RequestContent, @@ -2057,10 +1934,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "tags"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -2112,7 +1985,7 @@ impl BlobClient { /// /// * `tier` - Indicates the tier to be set on the blob. /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.Container.Blob.setTier")] + #[tracing::function("Storage.Blob.Blob.setTier")] pub async fn set_tier( &self, tier: AccessTier, @@ -2121,10 +1994,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "tier"); if let Some(snapshot) = options.snapshot { url.query_pairs_mut().append_pair("snapshot", &snapshot); @@ -2210,7 +2079,7 @@ impl BlobClient { /// * [`version_id`()](crate::generated::models::BlobClientStartCopyFromUrlResultHeaders::version_id) - x-ms-version-id /// /// [`BlobClientStartCopyFromUrlResultHeaders`]: crate::generated::models::BlobClientStartCopyFromUrlResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.startCopyFromUrl")] + #[tracing::function("Storage.Blob.Blob.startCopyFromUrl")] pub async fn start_copy_from_url( &self, copy_source: String, @@ -2219,10 +2088,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; if let Some(timeout) = options.timeout { url.query_pairs_mut() .append_pair("timeout", &timeout.to_string()); @@ -2350,7 +2215,7 @@ impl BlobClient { /// * [`date`()](crate::generated::models::BlobClientUndeleteResultHeaders::date) - Date /// /// [`BlobClientUndeleteResultHeaders`]: crate::generated::models::BlobClientUndeleteResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.undelete")] + #[tracing::function("Storage.Blob.Blob.undelete")] pub async fn undelete( &self, options: Option>, @@ -2358,10 +2223,6 @@ impl BlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "undelete"); if let Some(timeout) = options.timeout { url.query_pairs_mut() 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 44680f01de2..8c7ae54f7b7 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 @@ -3,29 +3,25 @@ // 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 crate::generated::{ - clients::BlobClient, - models::{ - BlobContainerClientAcquireLeaseOptions, BlobContainerClientAcquireLeaseResult, - BlobContainerClientBreakLeaseOptions, BlobContainerClientBreakLeaseResult, - BlobContainerClientChangeLeaseOptions, BlobContainerClientChangeLeaseResult, - BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, - BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccessPolicyOptions, - BlobContainerClientGetAccountInfoOptions, BlobContainerClientGetAccountInfoResult, - BlobContainerClientGetPropertiesOptions, BlobContainerClientGetPropertiesResult, - BlobContainerClientListBlobFlatSegmentOptions, - BlobContainerClientListBlobHierarchySegmentOptions, BlobContainerClientReleaseLeaseOptions, - BlobContainerClientReleaseLeaseResult, BlobContainerClientRenameOptions, - BlobContainerClientRenameResult, BlobContainerClientRenewLeaseOptions, - BlobContainerClientRenewLeaseResult, BlobContainerClientRestoreOptions, - BlobContainerClientRestoreResult, BlobContainerClientSetAccessPolicyOptions, - BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetMetadataOptions, - FilterBlobSegment, ListBlobsFlatSegmentResponse, ListBlobsHierarchySegmentResponse, - SignedIdentifier, - }, +use crate::generated::models::{ + BlobContainerClientAcquireLeaseOptions, BlobContainerClientAcquireLeaseResult, + BlobContainerClientBreakLeaseOptions, BlobContainerClientBreakLeaseResult, + BlobContainerClientChangeLeaseOptions, BlobContainerClientChangeLeaseResult, + BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, + BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccessPolicyOptions, + BlobContainerClientGetAccountInfoOptions, BlobContainerClientGetAccountInfoResult, + BlobContainerClientGetPropertiesOptions, BlobContainerClientGetPropertiesResult, + BlobContainerClientListBlobFlatSegmentOptions, + BlobContainerClientListBlobHierarchySegmentOptions, BlobContainerClientReleaseLeaseOptions, + BlobContainerClientReleaseLeaseResult, BlobContainerClientRenameOptions, + BlobContainerClientRenameResult, BlobContainerClientRenewLeaseOptions, + BlobContainerClientRenewLeaseResult, BlobContainerClientRestoreOptions, + BlobContainerClientRestoreResult, BlobContainerClientSetAccessPolicyOptions, + BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetMetadataOptions, + FilterBlobSegment, ListBlobsFlatSegmentResponse, ListBlobsHierarchySegmentResponse, + SignedIdentifier, }; use azure_core::{ - async_runtime::get_async_runtime, credentials::TokenCredential, error::CheckSuccessOptions, fmt::SafeDebug, @@ -42,7 +38,6 @@ use std::{collections::HashMap, sync::Arc}; #[tracing::client] pub struct BlobContainerClient { - pub(crate) container_name: String, pub(crate) endpoint: Url, pub(crate) pipeline: Pipeline, pub(crate) version: String, @@ -65,13 +60,11 @@ impl BlobContainerClient { /// * `endpoint` - Service host /// * `credential` - An implementation of [`TokenCredential`](azure_core::credentials::TokenCredential) that can provide an /// Entra ID token to use when authenticating. - /// * `container_name` - The name of the container. /// * `options` - Optional configuration for the client. #[tracing::new("Storage.Blob.Container")] pub fn new( endpoint: &str, credential: Arc, - container_name: String, options: Option, ) -> Result { let options = options.unwrap_or_default(); @@ -87,7 +80,6 @@ impl BlobContainerClient { vec!["https://storage.azure.com/.default"], )); Ok(Self { - container_name, endpoint, version: options.version, pipeline: Pipeline::new( @@ -154,7 +146,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_key_only("acquire") .append_pair("comp", "lease") @@ -240,7 +231,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_key_only("break") .append_pair("comp", "lease") @@ -330,7 +320,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_key_only("change") .append_pair("comp", "lease") @@ -384,7 +373,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut().append_pair("restype", "container"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -443,7 +431,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut().append_pair("restype", "container"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -496,7 +483,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "blobs") .append_pair("restype", "container"); @@ -591,7 +577,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "acl") .append_pair("restype", "container"); @@ -642,20 +627,21 @@ impl BlobContainerClient { /// async fn example() -> Result<()> { /// let response: Response = unimplemented!(); /// // Access response headers + /// if let Some(date) = response.date()? { + /// println!("Date: {:?}", date); + /// } /// if let Some(account_kind) = response.account_kind()? { /// println!("x-ms-account-kind: {:?}", account_kind); /// } /// if let Some(is_hierarchical_namespace_enabled) = response.is_hierarchical_namespace_enabled()? { /// println!("x-ms-is-hns-enabled: {:?}", is_hierarchical_namespace_enabled); /// } - /// if let Some(sku_name) = response.sku_name()? { - /// println!("x-ms-sku-name: {:?}", sku_name); - /// } /// Ok(()) /// } /// ``` /// /// ### Available headers + /// * [`date`()](crate::generated::models::BlobContainerClientGetAccountInfoResultHeaders::date) - Date /// * [`account_kind`()](crate::generated::models::BlobContainerClientGetAccountInfoResultHeaders::account_kind) - x-ms-account-kind /// * [`is_hierarchical_namespace_enabled`()](crate::generated::models::BlobContainerClientGetAccountInfoResultHeaders::is_hierarchical_namespace_enabled) - x-ms-is-hns-enabled /// * [`sku_name`()](crate::generated::models::BlobContainerClientGetAccountInfoResultHeaders::sku_name) - x-ms-sku-name @@ -669,7 +655,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "properties") .append_pair("restype", "account"); @@ -699,22 +684,6 @@ impl BlobContainerClient { Ok(rsp.into()) } - /// Returns a new instance of BlobClient. - /// - /// # Arguments - /// - /// * `blob_name` - The name of the blob. - #[tracing::subclient] - pub fn get_blob_client(&self, blob_name: String) -> BlobClient { - BlobClient { - blob_name, - container_name: self.container_name.clone(), - endpoint: self.endpoint.clone(), - pipeline: self.pipeline.clone(), - version: self.version.clone(), - } - } - /// returns all user-defined metadata and system properties for the specified container. The data returned does not include /// the container's list of blobs /// @@ -769,7 +738,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut().append_pair("restype", "container"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -836,7 +804,6 @@ impl BlobContainerClient { 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") @@ -905,8 +872,6 @@ impl BlobContainerClient { }), ) .await?; - // Because serialization can be a CPU intensive operation, yield the CPU before executing it.. - get_async_runtime().yield_now().await; let (status, headers, body) = rsp.deconstruct(); let res: ListBlobsFlatSegmentResponse = xml::from_xml(&body)?; let rsp = RawResponse::from_bytes(status, headers, body).into(); @@ -963,7 +928,6 @@ impl BlobContainerClient { 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") @@ -1094,7 +1058,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "lease") .append_key_only("release") @@ -1171,7 +1134,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "rename") .append_pair("restype", "container"); @@ -1252,7 +1214,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "lease") .append_key_only("renew") @@ -1327,7 +1288,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "undelete") .append_pair("restype", "container"); @@ -1410,7 +1370,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "acl") .append_pair("restype", "container"); @@ -1468,7 +1427,6 @@ impl BlobContainerClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - url = url.join(&self.container_name)?; url.query_pairs_mut() .append_pair("comp", "metadata") .append_pair("restype", "container"); 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 6ffc1f0d4f4..d61acb91559 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 @@ -3,16 +3,13 @@ // 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 crate::generated::{ - clients::BlobContainerClient, - models::{ - BlobServiceClientFindBlobsByTagsOptions, BlobServiceClientGetAccountInfoOptions, - BlobServiceClientGetAccountInfoResult, BlobServiceClientGetPropertiesOptions, - BlobServiceClientGetStatisticsOptions, BlobServiceClientGetUserDelegationKeyOptions, - BlobServiceClientListContainersSegmentOptions, BlobServiceClientSetPropertiesOptions, - BlobServiceProperties, FilterBlobSegment, KeyInfo, ListContainersSegmentResponse, - StorageServiceStats, UserDelegationKey, - }, +use crate::generated::models::{ + BlobServiceClientFindBlobsByTagsOptions, BlobServiceClientGetAccountInfoOptions, + BlobServiceClientGetAccountInfoResult, BlobServiceClientGetPropertiesOptions, + BlobServiceClientGetStatisticsOptions, BlobServiceClientGetUserDelegationKeyOptions, + BlobServiceClientListContainersSegmentOptions, BlobServiceClientSetPropertiesOptions, + BlobServiceProperties, FilterBlobSegment, KeyInfo, ListContainersSegmentResponse, + StorageServiceStats, UserDelegationKey, }; use azure_core::{ credentials::TokenCredential, @@ -53,7 +50,7 @@ impl BlobServiceClient { /// * `credential` - An implementation of [`TokenCredential`](azure_core::credentials::TokenCredential) that can provide an /// Entra ID token to use when authenticating. /// * `options` - Optional configuration for the client. - #[tracing::new("Storage.Blob")] + #[tracing::new("Storage.Blob.Service")] pub fn new( endpoint: &str, credential: Arc, @@ -96,7 +93,7 @@ impl BlobServiceClient { /// /// * `filter_expression` - Filters the results to return only to return only blobs whose tags match the specified expression. /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.findBlobsByTags")] + #[tracing::function("Storage.Blob.Service.findBlobsByTags")] pub async fn find_blobs_by_tags( &self, filter_expression: &str, @@ -169,26 +166,27 @@ impl BlobServiceClient { /// async fn example() -> Result<()> { /// let response: Response = unimplemented!(); /// // Access response headers + /// if let Some(date) = response.date()? { + /// println!("Date: {:?}", date); + /// } /// if let Some(account_kind) = response.account_kind()? { /// println!("x-ms-account-kind: {:?}", account_kind); /// } /// if let Some(is_hierarchical_namespace_enabled) = response.is_hierarchical_namespace_enabled()? { /// println!("x-ms-is-hns-enabled: {:?}", is_hierarchical_namespace_enabled); /// } - /// if let Some(sku_name) = response.sku_name()? { - /// println!("x-ms-sku-name: {:?}", sku_name); - /// } /// Ok(()) /// } /// ``` /// /// ### Available headers + /// * [`date`()](crate::generated::models::BlobServiceClientGetAccountInfoResultHeaders::date) - Date /// * [`account_kind`()](crate::generated::models::BlobServiceClientGetAccountInfoResultHeaders::account_kind) - x-ms-account-kind /// * [`is_hierarchical_namespace_enabled`()](crate::generated::models::BlobServiceClientGetAccountInfoResultHeaders::is_hierarchical_namespace_enabled) - x-ms-is-hns-enabled /// * [`sku_name`()](crate::generated::models::BlobServiceClientGetAccountInfoResultHeaders::sku_name) - x-ms-sku-name /// /// [`BlobServiceClientGetAccountInfoResultHeaders`]: crate::generated::models::BlobServiceClientGetAccountInfoResultHeaders - #[tracing::function("Storage.Blob.getAccountInfo")] + #[tracing::function("Storage.Blob.Service.getAccountInfo")] pub async fn get_account_info( &self, options: Option>, @@ -225,28 +223,13 @@ impl BlobServiceClient { Ok(rsp.into()) } - /// Returns a new instance of BlobContainerClient. - /// - /// # Arguments - /// - /// * `container_name` - The name of the container. - #[tracing::subclient] - pub fn get_blob_container_client(&self, container_name: String) -> BlobContainerClient { - BlobContainerClient { - container_name, - endpoint: self.endpoint.clone(), - pipeline: self.pipeline.clone(), - version: self.version.clone(), - } - } - /// Retrieves properties of a storage account's Blob service, including properties for Storage Analytics and CORS (Cross-Origin /// Resource Sharing) rules. /// /// # Arguments /// /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.getProperties")] + #[tracing::function("Storage.Blob.Service.getProperties")] pub async fn get_properties( &self, options: Option>, @@ -313,7 +296,7 @@ impl BlobServiceClient { /// * [`date`()](crate::generated::models::StorageServiceStatsHeaders::date) - Date /// /// [`StorageServiceStatsHeaders`]: crate::generated::models::StorageServiceStatsHeaders - #[tracing::function("Storage.Blob.getStatistics")] + #[tracing::function("Storage.Blob.Service.getStatistics")] pub async fn get_statistics( &self, options: Option>, @@ -380,7 +363,7 @@ impl BlobServiceClient { /// * [`date`()](crate::generated::models::UserDelegationKeyHeaders::date) - Date /// /// [`UserDelegationKeyHeaders`]: crate::generated::models::UserDelegationKeyHeaders - #[tracing::function("Storage.Blob.getUserDelegationKey")] + #[tracing::function("Storage.Blob.Service.getUserDelegationKey")] pub async fn get_user_delegation_key( &self, key_info: RequestContent, @@ -425,7 +408,7 @@ impl BlobServiceClient { /// # Arguments /// /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.listContainersSegment")] + #[tracing::function("Storage.Blob.Service.listContainersSegment")] pub fn list_containers_segment( &self, options: Option>, @@ -517,12 +500,12 @@ impl BlobServiceClient { /// /// # Arguments /// - /// * `blob_service_properties` - The storage service properties to set. + /// * `storage_service_properties` - The storage service properties to set. /// * `options` - Optional parameters for the request. - #[tracing::function("Storage.Blob.setProperties")] + #[tracing::function("Storage.Blob.Service.setProperties")] pub async fn set_properties( &self, - blob_service_properties: RequestContent, + storage_service_properties: RequestContent, options: Option>, ) -> Result> { let options = options.unwrap_or_default(); @@ -541,7 +524,7 @@ impl BlobServiceClient { request.insert_header("x-ms-client-request-id", client_request_id); } request.insert_header("x-ms-version", &self.version); - request.set_body(blob_service_properties); + request.set_body(storage_service_properties); let rsp = self .pipeline .send( 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 29115f7aeb2..0ecbfbcdf3d 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 @@ -29,8 +29,6 @@ use std::sync::Arc; #[tracing::client] pub struct BlockBlobClient { - pub(crate) blob_name: String, - pub(crate) container_name: String, pub(crate) endpoint: Url, pub(crate) pipeline: Pipeline, pub(crate) version: String, @@ -53,15 +51,11 @@ impl BlockBlobClient { /// * `endpoint` - Service host /// * `credential` - An implementation of [`TokenCredential`](azure_core::credentials::TokenCredential) that can provide an /// Entra ID token to use when authenticating. - /// * `container_name` - The name of the container. - /// * `blob_name` - The name of the blob. /// * `options` - Optional configuration for the client. - #[tracing::new("Storage.Blob.Container.Blob.BlockBlob")] + #[tracing::new("Storage.Blob.BlockBlob")] pub fn new( endpoint: &str, credential: Arc, - container_name: String, - blob_name: String, options: Option, ) -> Result { let options = options.unwrap_or_default(); @@ -77,8 +71,6 @@ impl BlockBlobClient { vec!["https://storage.azure.com/.default"], )); Ok(Self { - blob_name, - container_name, endpoint, version: options.version, pipeline: Pipeline::new( @@ -144,7 +136,7 @@ impl BlockBlobClient { /// * [`version_id`()](crate::generated::models::BlockBlobClientCommitBlockListResultHeaders::version_id) - x-ms-version-id /// /// [`BlockBlobClientCommitBlockListResultHeaders`]: crate::generated::models::BlockBlobClientCommitBlockListResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.BlockBlob.commitBlockList")] + #[tracing::function("Storage.Blob.BlockBlob.commitBlockList")] pub async fn commit_block_list( &self, blocks: RequestContent, @@ -153,10 +145,6 @@ impl BlockBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "blocklist"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -306,7 +294,7 @@ impl BlockBlobClient { /// * [`blob_content_length`()](crate::generated::models::BlockListHeaders::blob_content_length) - x-ms-blob-content-length /// /// [`BlockListHeaders`]: crate::generated::models::BlockListHeaders - #[tracing::function("Storage.Blob.Container.Blob.BlockBlob.getBlockList")] + #[tracing::function("Storage.Blob.BlockBlob.getBlockList")] pub async fn get_block_list( &self, list_type: BlockListType, @@ -315,10 +303,6 @@ impl BlockBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "blocklist"); url.query_pairs_mut() .append_pair("blocklisttype", list_type.as_ref()); @@ -367,7 +351,7 @@ impl BlockBlobClient { /// /// ## Response Headers /// - /// The returned [`Response`](azure_core::http::Response) implements the [`BlockBlobClientQueryResultHeaders`] trait, which provides + /// The returned [`AsyncResponse`](azure_core::http::AsyncResponse) implements the [`BlockBlobClientQueryResultHeaders`] trait, which provides /// access to response headers. For example: /// /// ```no_run @@ -421,7 +405,7 @@ impl BlockBlobClient { /// * [`is_server_encrypted`()](crate::generated::models::BlockBlobClientQueryResultHeaders::is_server_encrypted) - x-ms-server-encrypted /// /// [`BlockBlobClientQueryResultHeaders`]: crate::generated::models::BlockBlobClientQueryResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.BlockBlob.query")] + #[tracing::function("Storage.Blob.BlockBlob.query")] pub async fn query( &self, query_request: RequestContent, @@ -430,10 +414,6 @@ impl BlockBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "query"); if let Some(snapshot) = options.snapshot { url.query_pairs_mut().append_pair("snapshot", &snapshot); @@ -539,7 +519,7 @@ impl BlockBlobClient { /// * [`is_server_encrypted`()](crate::generated::models::BlockBlobClientStageBlockResultHeaders::is_server_encrypted) - x-ms-request-server-encrypted /// /// [`BlockBlobClientStageBlockResultHeaders`]: crate::generated::models::BlockBlobClientStageBlockResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.BlockBlob.stageBlock")] + #[tracing::function("Storage.Blob.BlockBlob.stageBlock")] pub async fn stage_block( &self, block_id: &[u8], @@ -550,10 +530,6 @@ impl BlockBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "block"); url.query_pairs_mut() .append_pair("blockid", &encode(block_id)); @@ -663,7 +639,7 @@ impl BlockBlobClient { /// * [`is_server_encrypted`()](crate::generated::models::BlockBlobClientStageBlockFromUrlResultHeaders::is_server_encrypted) - x-ms-request-server-encrypted /// /// [`BlockBlobClientStageBlockFromUrlResultHeaders`]: crate::generated::models::BlockBlobClientStageBlockFromUrlResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.BlockBlob.stageBlockFromUrl")] + #[tracing::function("Storage.Blob.BlockBlob.stageBlockFromUrl")] pub async fn stage_block_from_url( &self, block_id: &[u8], @@ -674,10 +650,6 @@ impl BlockBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "block") .append_key_only("fromURL"); @@ -807,7 +779,7 @@ impl BlockBlobClient { /// * [`version_id`()](crate::generated::models::BlockBlobClientUploadResultHeaders::version_id) - x-ms-version-id /// /// [`BlockBlobClientUploadResultHeaders`]: crate::generated::models::BlockBlobClientUploadResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.BlockBlob.upload")] + #[tracing::function("Storage.Blob.BlockBlob.upload")] pub async fn upload( &self, body: RequestContent, @@ -817,10 +789,6 @@ impl BlockBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; if let Some(timeout) = options.timeout { url.query_pairs_mut() .append_pair("timeout", &timeout.to_string()); @@ -968,18 +936,19 @@ impl BlockBlobClient { /// if let Some(content_md5) = response.content_md5()? { /// println!("Content-MD5: {:?}", content_md5); /// } + /// if let Some(date) = response.date()? { + /// println!("Date: {:?}", date); + /// } /// if let Some(last_modified) = response.last_modified()? { /// println!("Last-Modified: {:?}", last_modified); /// } - /// if let Some(etag) = response.etag()? { - /// println!("etag: {:?}", etag); - /// } /// Ok(()) /// } /// ``` /// /// ### Available headers /// * [`content_md5`()](crate::generated::models::BlockBlobClientUploadBlobFromUrlResultHeaders::content_md5) - Content-MD5 + /// * [`date`()](crate::generated::models::BlockBlobClientUploadBlobFromUrlResultHeaders::date) - Date /// * [`last_modified`()](crate::generated::models::BlockBlobClientUploadBlobFromUrlResultHeaders::last_modified) - Last-Modified /// * [`etag`()](crate::generated::models::BlockBlobClientUploadBlobFromUrlResultHeaders::etag) - etag /// * [`encryption_key_sha256`()](crate::generated::models::BlockBlobClientUploadBlobFromUrlResultHeaders::encryption_key_sha256) - x-ms-encryption-key-sha256 @@ -988,7 +957,7 @@ impl BlockBlobClient { /// * [`version_id`()](crate::generated::models::BlockBlobClientUploadBlobFromUrlResultHeaders::version_id) - x-ms-version-id /// /// [`BlockBlobClientUploadBlobFromUrlResultHeaders`]: crate::generated::models::BlockBlobClientUploadBlobFromUrlResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.BlockBlob.uploadBlobFromUrl")] + #[tracing::function("Storage.Blob.BlockBlob.uploadBlobFromUrl")] pub async fn upload_blob_from_url( &self, copy_source: String, @@ -997,10 +966,6 @@ impl BlockBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("BlockBlob") .append_key_only("fromUrl"); 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 9e6d8f36504..dc9be765476 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 @@ -31,8 +31,6 @@ use std::sync::Arc; #[tracing::client] pub struct PageBlobClient { - pub(crate) blob_name: String, - pub(crate) container_name: String, pub(crate) endpoint: Url, pub(crate) pipeline: Pipeline, pub(crate) version: String, @@ -55,15 +53,11 @@ impl PageBlobClient { /// * `endpoint` - Service host /// * `credential` - An implementation of [`TokenCredential`](azure_core::credentials::TokenCredential) that can provide an /// Entra ID token to use when authenticating. - /// * `container_name` - The name of the container. - /// * `blob_name` - The name of the blob. /// * `options` - Optional configuration for the client. - #[tracing::new("Storage.Blob.Container.Blob.PageBlob")] + #[tracing::new("Storage.Blob.PageBlob")] pub fn new( endpoint: &str, credential: Arc, - container_name: String, - blob_name: String, options: Option, ) -> Result { let options = options.unwrap_or_default(); @@ -79,8 +73,6 @@ impl PageBlobClient { vec!["https://storage.azure.com/.default"], )); Ok(Self { - blob_name, - container_name, endpoint, version: options.version, pipeline: Pipeline::new( @@ -138,7 +130,7 @@ impl PageBlobClient { /// * [`content_crc64`()](crate::generated::models::PageBlobClientClearPagesResultHeaders::content_crc64) - x-ms-content-crc64 /// /// [`PageBlobClientClearPagesResultHeaders`]: crate::generated::models::PageBlobClientClearPagesResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.clearPages")] + #[tracing::function("Storage.Blob.PageBlob.clearPages")] pub async fn clear_pages( &self, range: String, @@ -147,10 +139,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("clear") .append_pair("comp", "page"); @@ -279,7 +267,7 @@ impl PageBlobClient { /// * [`copy_status`()](crate::generated::models::PageBlobClientCopyIncrementalResultHeaders::copy_status) - x-ms-copy-status /// /// [`PageBlobClientCopyIncrementalResultHeaders`]: crate::generated::models::PageBlobClientCopyIncrementalResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.copyIncremental")] + #[tracing::function("Storage.Blob.PageBlob.copyIncremental")] pub async fn copy_incremental( &self, copy_source: String, @@ -288,10 +276,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "incrementalcopy"); if let Some(timeout) = options.timeout { url.query_pairs_mut() @@ -377,7 +361,7 @@ impl PageBlobClient { /// * [`version_id`()](crate::generated::models::PageBlobClientCreateResultHeaders::version_id) - x-ms-version-id /// /// [`PageBlobClientCreateResultHeaders`]: crate::generated::models::PageBlobClientCreateResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.create")] + #[tracing::function("Storage.Blob.PageBlob.create")] pub async fn create( &self, blob_content_length: u64, @@ -386,10 +370,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; if let Some(timeout) = options.timeout { url.query_pairs_mut() .append_pair("timeout", &timeout.to_string()); @@ -538,7 +518,7 @@ impl PageBlobClient { /// * [`blob_content_length`()](crate::generated::models::PageListHeaders::blob_content_length) - x-ms-blob-content-length /// /// [`PageListHeaders`]: crate::generated::models::PageListHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.getPageRanges")] + #[tracing::function("Storage.Blob.PageBlob.getPageRanges")] pub async fn get_page_ranges( &self, options: Option>, @@ -546,10 +526,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "pagelist"); if let Some(marker) = options.marker { url.query_pairs_mut().append_pair("marker", &marker); @@ -646,7 +622,7 @@ impl PageBlobClient { /// * [`blob_content_length`()](crate::generated::models::PageListHeaders::blob_content_length) - x-ms-blob-content-length /// /// [`PageListHeaders`]: crate::generated::models::PageListHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.getPageRangesDiff")] + #[tracing::function("Storage.Blob.PageBlob.getPageRangesDiff")] pub async fn get_page_ranges_diff( &self, options: Option>, @@ -654,10 +630,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "pagelist") .append_key_only("diff"); @@ -764,7 +736,7 @@ impl PageBlobClient { /// * [`blob_sequence_number`()](crate::generated::models::PageBlobClientResizeResultHeaders::blob_sequence_number) - x-ms-blob-sequence-number /// /// [`PageBlobClientResizeResultHeaders`]: crate::generated::models::PageBlobClientResizeResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.resize")] + #[tracing::function("Storage.Blob.PageBlob.resize")] pub async fn resize( &self, blob_content_length: u64, @@ -773,10 +745,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("Resize") .append_pair("comp", "properties"); @@ -879,7 +847,7 @@ impl PageBlobClient { /// * [`blob_sequence_number`()](crate::generated::models::PageBlobClientSetSequenceNumberResultHeaders::blob_sequence_number) - x-ms-blob-sequence-number /// /// [`PageBlobClientSetSequenceNumberResultHeaders`]: crate::generated::models::PageBlobClientSetSequenceNumberResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.setSequenceNumber")] + #[tracing::function("Storage.Blob.PageBlob.setSequenceNumber")] pub async fn set_sequence_number( &self, sequence_number_action: SequenceNumberActionType, @@ -888,10 +856,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - path = path.replace("{blobName}", &self.blob_name); - path = path.replace("{containerName}", &self.container_name); - url = url.join(&path)?; url.query_pairs_mut() .append_key_only("UpdateSequenceNumber") .append_pair("comp", "properties"); @@ -993,7 +957,7 @@ impl PageBlobClient { /// * [`is_server_encrypted`()](crate::generated::models::PageBlobClientUploadPagesResultHeaders::is_server_encrypted) - x-ms-request-server-encrypted /// /// [`PageBlobClientUploadPagesResultHeaders`]: crate::generated::models::PageBlobClientUploadPagesResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.uploadPages")] + #[tracing::function("Storage.Blob.PageBlob.uploadPages")] pub async fn upload_pages( &self, body: RequestContent, @@ -1004,10 +968,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "page") .append_key_only("update"); @@ -1156,7 +1116,7 @@ impl PageBlobClient { /// * [`is_server_encrypted`()](crate::generated::models::PageBlobClientUploadPagesFromUrlResultHeaders::is_server_encrypted) - x-ms-request-server-encrypted /// /// [`PageBlobClientUploadPagesFromUrlResultHeaders`]: crate::generated::models::PageBlobClientUploadPagesFromUrlResultHeaders - #[tracing::function("Storage.Blob.Container.Blob.PageBlob.uploadPagesFromUrl")] + #[tracing::function("Storage.Blob.PageBlob.uploadPagesFromUrl")] pub async fn upload_pages_from_url( &self, source_url: String, @@ -1168,10 +1128,6 @@ impl PageBlobClient { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); - let mut path = String::from("{containerName}/{blobName}"); - 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", "page") .append_key_only("fromUrl") 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 f6e99d85f43..1f97273c52f 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 @@ -1082,25 +1082,31 @@ impl BlobClientDownloadResultHeaders for AsyncResponse /// async fn example() -> Result<()> { /// let response: Response = unimplemented!(); /// // Access response headers +/// if let Some(date) = response.date()? { +/// println!("Date: {:?}", date); +/// } /// if let Some(account_kind) = response.account_kind()? { /// println!("x-ms-account-kind: {:?}", account_kind); /// } /// if let Some(is_hierarchical_namespace_enabled) = response.is_hierarchical_namespace_enabled()? { /// println!("x-ms-is-hns-enabled: {:?}", is_hierarchical_namespace_enabled); /// } -/// if let Some(sku_name) = response.sku_name()? { -/// println!("x-ms-sku-name: {:?}", sku_name); -/// } /// Ok(()) /// } /// ``` pub trait BlobClientGetAccountInfoResultHeaders: private::Sealed { + fn date(&self) -> Result>; fn account_kind(&self) -> Result>; fn is_hierarchical_namespace_enabled(&self) -> Result>; fn sku_name(&self) -> Result>; } impl BlobClientGetAccountInfoResultHeaders for Response { + /// UTC date/time value generated by the service that indicates the time at which the response was initiated + fn date(&self) -> Result> { + Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) + } + /// Identifies the account kind fn account_kind(&self) -> Result> { Headers::get_optional_as(self.headers(), &ACCOUNT_KIND) @@ -1929,19 +1935,20 @@ impl BlobContainerClientChangeLeaseResultHeaders /// async fn example() -> Result<()> { /// let response: Response = unimplemented!(); /// // Access response headers +/// if let Some(date) = response.date()? { +/// println!("Date: {:?}", date); +/// } /// if let Some(account_kind) = response.account_kind()? { /// println!("x-ms-account-kind: {:?}", account_kind); /// } /// if let Some(is_hierarchical_namespace_enabled) = response.is_hierarchical_namespace_enabled()? { /// println!("x-ms-is-hns-enabled: {:?}", is_hierarchical_namespace_enabled); /// } -/// if let Some(sku_name) = response.sku_name()? { -/// println!("x-ms-sku-name: {:?}", sku_name); -/// } /// Ok(()) /// } /// ``` pub trait BlobContainerClientGetAccountInfoResultHeaders: private::Sealed { + fn date(&self) -> Result>; fn account_kind(&self) -> Result>; fn is_hierarchical_namespace_enabled(&self) -> Result>; fn sku_name(&self) -> Result>; @@ -1950,6 +1957,11 @@ pub trait BlobContainerClientGetAccountInfoResultHeaders: private::Sealed { impl BlobContainerClientGetAccountInfoResultHeaders for Response { + /// UTC date/time value generated by the service that indicates the time at which the response was initiated + fn date(&self) -> Result> { + Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) + } + /// Identifies the account kind fn account_kind(&self) -> Result> { Headers::get_optional_as(self.headers(), &ACCOUNT_KIND) @@ -2284,19 +2296,20 @@ impl BlobContainerClientSetAccessPolicyResultHeaders /// async fn example() -> Result<()> { /// let response: Response = unimplemented!(); /// // Access response headers +/// if let Some(date) = response.date()? { +/// println!("Date: {:?}", date); +/// } /// if let Some(account_kind) = response.account_kind()? { /// println!("x-ms-account-kind: {:?}", account_kind); /// } /// if let Some(is_hierarchical_namespace_enabled) = response.is_hierarchical_namespace_enabled()? { /// println!("x-ms-is-hns-enabled: {:?}", is_hierarchical_namespace_enabled); /// } -/// if let Some(sku_name) = response.sku_name()? { -/// println!("x-ms-sku-name: {:?}", sku_name); -/// } /// Ok(()) /// } /// ``` pub trait BlobServiceClientGetAccountInfoResultHeaders: private::Sealed { + fn date(&self) -> Result>; fn account_kind(&self) -> Result>; fn is_hierarchical_namespace_enabled(&self) -> Result>; fn sku_name(&self) -> Result>; @@ -2305,6 +2318,11 @@ pub trait BlobServiceClientGetAccountInfoResultHeaders: private::Sealed { impl BlobServiceClientGetAccountInfoResultHeaders for Response { + /// UTC date/time value generated by the service that indicates the time at which the response was initiated + fn date(&self) -> Result> { + Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) + } + /// Identifies the account kind fn account_kind(&self) -> Result> { Headers::get_optional_as(self.headers(), &ACCOUNT_KIND) @@ -2816,17 +2834,18 @@ impl BlockBlobClientStageBlockResultHeaders /// if let Some(content_md5) = response.content_md5()? { /// println!("Content-MD5: {:?}", content_md5); /// } +/// if let Some(date) = response.date()? { +/// println!("Date: {:?}", date); +/// } /// if let Some(last_modified) = response.last_modified()? { /// println!("Last-Modified: {:?}", last_modified); /// } -/// if let Some(etag) = response.etag()? { -/// println!("etag: {:?}", etag); -/// } /// Ok(()) /// } /// ``` pub trait BlockBlobClientUploadBlobFromUrlResultHeaders: private::Sealed { fn content_md5(&self) -> Result>>; + fn date(&self) -> Result>; fn last_modified(&self) -> Result>; fn etag(&self) -> Result>; fn encryption_key_sha256(&self) -> Result>; @@ -2844,6 +2863,11 @@ impl BlockBlobClientUploadBlobFromUrlResultHeaders Headers::get_optional_with(self.headers(), &CONTENT_MD5, |h| decode(h.as_str())) } + /// UTC date/time value generated by the service that indicates the time at which the response was initiated + fn date(&self) -> Result> { + Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) + } + /// The date/time that the container was last modified. fn last_modified(&self) -> Result> { Headers::get_optional_with(self.headers(), &LAST_MODIFIED, |h| { 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 379761bad03..44a18a2f400 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 @@ -242,7 +242,7 @@ pub struct BlobItemInternal { #[serde(rename = "Deleted", skip_serializing_if = "Option::is_none")] pub deleted: Option, - /// Whether the blog has versions only. + /// Whether the blob has versions only. #[serde(rename = "HasVersionsOnly", skip_serializing_if = "Option::is_none")] pub has_versions_only: Option, @@ -450,7 +450,7 @@ pub struct BlobPropertiesInternal { #[serde(rename = "EncryptionScope", skip_serializing_if = "Option::is_none")] pub encryption_scope: Option, - /// The blog ETag. + /// The blob ETag. #[serde(rename = "Etag", skip_serializing_if = "Option::is_none")] pub etag: Option, @@ -479,7 +479,7 @@ pub struct BlobPropertiesInternal { )] pub immutability_policy_mode: Option, - /// Whether the blog is incremental copy. + /// Whether the blob is incremental copy. #[serde(rename = "IncrementalCopy", skip_serializing_if = "Option::is_none")] pub incremental_copy: Option, @@ -532,7 +532,7 @@ pub struct BlobPropertiesInternal { )] pub remaining_retention_days: Option, - /// Whether the blog is encrypted on the server. + /// Whether the blob is encrypted on the server. #[serde(rename = "ServerEncrypted", skip_serializing_if = "Option::is_none")] pub server_encrypted: Option, diff --git a/sdk/storage/azure_storage_blob/src/models/extensions.rs b/sdk/storage/azure_storage_blob/src/models/extensions.rs index 03246605a86..02aa70f331e 100644 --- a/sdk/storage/azure_storage_blob/src/models/extensions.rs +++ b/sdk/storage/azure_storage_blob/src/models/extensions.rs @@ -2,8 +2,9 @@ // Licensed under the MIT License. use crate::models::{ - AppendBlobClientCreateOptions, BlobTag, BlobTags, BlockBlobClientUploadBlobFromUrlOptions, - BlockBlobClientUploadOptions, PageBlobClientCreateOptions, + AppendBlobClientCreateOptions, BlobName, BlobTag, BlobTags, + BlockBlobClientUploadBlobFromUrlOptions, BlockBlobClientUploadOptions, + PageBlobClientCreateOptions, }; use azure_core::error::ErrorKind; use std::collections::HashMap; diff --git a/sdk/storage/azure_storage_blob/src/parsers.rs b/sdk/storage/azure_storage_blob/src/parsers.rs index 9bfed276b18..c6b9c47c974 100644 --- a/sdk/storage/azure_storage_blob/src/parsers.rs +++ b/sdk/storage/azure_storage_blob/src/parsers.rs @@ -4,6 +4,7 @@ use crate::models::{BlobTag, BlobTags}; use std::collections::HashMap; use std::io::{Error, ErrorKind}; +use url::Url; /// Takes in an offset and a length, verifies alignment to a 512-byte boundary, and /// returns the HTTP range in String format. diff --git a/sdk/storage/azure_storage_blob/tests/append_blob_client.rs b/sdk/storage/azure_storage_blob/tests/append_blob_client.rs index dbd1d35ba42..17f544be65b 100644 --- a/sdk/storage/azure_storage_blob/tests/append_blob_client.rs +++ b/sdk/storage/azure_storage_blob/tests/append_blob_client.rs @@ -14,7 +14,7 @@ async fn test_create_append_blob(ctx: TestContext) -> Result<(), Box> // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let append_blob_client = blob_client.append_blob_client(); append_blob_client.create(None).await?; @@ -36,7 +36,7 @@ async fn test_append_block(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let append_blob_client = blob_client.append_blob_client(); append_blob_client.create(None).await?; let mut block_1 = b"hello".to_vec(); @@ -76,21 +76,15 @@ async fn test_append_block_from_url(ctx: TestContext) -> Result<(), Box Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let append_blob_client = blob_client.append_blob_client(); append_blob_client.create(None).await?; let test_block = b"test".to_vec(); diff --git a/sdk/storage/azure_storage_blob/tests/blob_client.rs b/sdk/storage/azure_storage_blob/tests/blob_client.rs index 100d21f52f7..8ea91dfd660 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_client.rs @@ -2,29 +2,33 @@ // Licensed under the MIT License. use azure_core::{ - http::{RequestContent, StatusCode}, + http::{ClientOptions, RequestContent, StatusCode}, Bytes, }; use azure_core_test::{recorded, Matcher, TestContext}; -use azure_storage_blob::models::{ - AccessTier, AccountKind, BlobClientAcquireLeaseResultHeaders, - BlobClientChangeLeaseResultHeaders, BlobClientDownloadOptions, BlobClientDownloadResultHeaders, - BlobClientGetAccountInfoResultHeaders, BlobClientGetPropertiesOptions, - BlobClientGetPropertiesResultHeaders, BlobClientSetMetadataOptions, - BlobClientSetPropertiesOptions, BlobClientSetTierOptions, BlockBlobClientUploadOptions, - LeaseState, +use azure_storage_blob::{ + models::{ + AccessTier, AccountKind, BlobClientAcquireLeaseResultHeaders, + BlobClientChangeLeaseResultHeaders, BlobClientDownloadOptions, + BlobClientDownloadResultHeaders, BlobClientGetAccountInfoResultHeaders, + BlobClientGetPropertiesOptions, BlobClientGetPropertiesResultHeaders, + BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTierOptions, + BlockBlobClientUploadOptions, LeaseState, + }, + BlobClient, BlobClientOptions, BlobContainerClient, BlobContainerClientOptions, }; - use azure_storage_blob_test::{create_test_blob, get_blob_name, get_container_client}; +use futures::TryStreamExt; use std::{collections::HashMap, error::Error, time::Duration}; use tokio::time; +use typespec_client_core::http::Url; #[recorded::test] async fn test_get_blob_properties(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, false).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); // Container Doesn't Exist Scenario let response = blob_client.get_properties(None).await; @@ -62,7 +66,7 @@ async fn test_set_blob_properties(ctx: TestContext) -> Result<(), Box // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); create_test_blob(&blob_client, None, None).await?; // Set Content Settings @@ -92,7 +96,7 @@ async fn test_upload_blob(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let data = b"hello rusty world"; @@ -166,7 +170,7 @@ async fn test_delete_blob(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); create_test_blob(&blob_client, None, None).await?; // Existence Check @@ -189,7 +193,7 @@ async fn test_download_blob(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let data = b"hello rusty world"; blob_client @@ -222,7 +226,7 @@ async fn test_set_blob_metadata(ctx: TestContext) -> Result<(), Box> let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let data = b"hello rusty world"; // Upload Blob With Metadata @@ -270,7 +274,7 @@ async fn test_set_access_tier(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); create_test_blob(&blob_client, None, None).await?; let original_response = blob_client.get_properties(None).await?; @@ -295,8 +299,8 @@ async fn test_blob_lease_operations(ctx: TestContext) -> Result<(), Box Result<(), Box Result<(), Box> { let recording = ctx.recording(); recording.set_matcher(Matcher::BodilessMatcher).await?; let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); create_test_blob(&blob_client, None, None).await?; // Set Tags with Tags Specified @@ -470,9 +474,10 @@ async fn test_blob_tags(ctx: TestContext) -> Result<(), Box> { #[recorded::test] async fn test_get_account_info(ctx: TestContext) -> Result<(), Box> { // Recording Setup + let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); // Act let response = blob_client.get_account_info(None).await?; @@ -486,3 +491,156 @@ async fn test_get_account_info(ctx: TestContext) -> Result<(), Box> { Ok(()) } + +#[recorded::test] +async fn test_encoding_edge_cases(ctx: TestContext) -> Result<(), Box> { + // Recording Setup + let recording = ctx.recording(); + let mut client_options = ClientOptions::default(); + recording.instrument(&mut client_options); + + // ContainerClient Options + let container_client_options = BlobContainerClientOptions { + client_options: client_options.clone(), + ..Default::default() + }; + + // BlobClient Options + let blob_client_options = BlobClientOptions { + client_options: client_options.clone(), + ..Default::default() + }; + + // Endpoint + let endpoint = format!( + "https://{}.blob.core.windows.net/", + recording.var("AZURE_STORAGE_ACCOUNT_NAME", None).as_str() + ); + + let container_name = "test-container-encoding-edge-cases"; + // Create Container & Container Client + let container_client = BlobContainerClient::new( + &endpoint, + container_name, + Some(recording.credential()), + Some(container_client_options.clone()), + )?; + container_client.create_container(None).await?; + + // Test Data for Parameterization + let test_cases = [ + // Basic + paths - combines simple case with forward slashes (virtual directories) + "folder/subfolder/file.txt", + // Reserved URL characters requiring encoding - combines spaces, %, ?, &, =, #, + in one test + "Q4 2024/report 50%+tax?final=true&approved#section-1.pdf", + // Unicode (multi-script) + unreserved chars - combines UTF-8 with chars that don't need encoding + "カニのフェリス_🦀.txt", + // Consecutive special chars + "path\\\\with___...~~~consecutive///chars", + // Additional reserved chars: parentheses, brackets, colon, quotes, leading/trailing spaces + " file (copy) [2024]:version'1'.txt ", + // Mix of forward and backslashes to test normalization/preservation + "forward/back\\forward/back\\", + // Test of already encoded characters but we want them preserved as-is + "data%20set%ferris%3D1%the%23crab%2D2", + ]; + for blob_name in test_cases { + // Test Case 1: Initialize BlobClient using new() constructor + let blob_client_new = BlobClient::new( + &endpoint, + container_name, + blob_name, + Some(recording.credential()), + Some(blob_client_options.clone()), + )?; + + // Upload Blob + blob_client_new + .upload( + RequestContent::from(b"hello rusty world".to_vec()), + true, + 17, + None, + ) + .await?; + + // Get Properties + let properties = blob_client_new.get_properties(None).await?; + assert_eq!(17, properties.content_length()?.unwrap()); + + // Test Case 2: Initialize BlobClient using from_blob_url(), separate path segments + let mut blob_url = Url::parse(&endpoint)?; + blob_url + .path_segments_mut() + .expect("Storage Endpoint must be a valid base URL with http/https scheme") + .push(container_name) + .push(blob_name); + + let blob_client_from_url = BlobClient::from_url( + blob_url, + Some(recording.credential()), + Some(blob_client_options.clone()), + )?; + + // Upload Blob + blob_client_from_url + .upload( + RequestContent::from(b"hello rusty world".to_vec()), + true, + 17, + None, + ) + .await?; + + // Get Properties + let properties = blob_client_from_url.get_properties(None).await?; + assert_eq!(17, properties.content_length()?.unwrap()); + + // Test Case 3: Initialize BlobClient using ContainerClient accessor + let blob_client_from_cc = container_client.blob_client(blob_name); + + // Upload Blob + blob_client_from_cc + .upload( + RequestContent::from(b"hello rusty world".to_vec()), + true, + 17, + None, + ) + .await?; + + // Get Properties + let properties = blob_client_from_cc.get_properties(None).await?; + assert_eq!(17, properties.content_length()?.unwrap()); + } + + // Check name equality for all test cases + 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()?; + let blob_items = list_blob_segment_response.segment.blob_items; + + // Ensure we have the expected number of blobs + assert_eq!(test_cases.len(), blob_items.len()); + + // Extract all blob names from list_blobs() response + let listed_blob_names: Vec = blob_items + .iter() + .map(|blob| blob.name.clone().unwrap().content.unwrap()) + .collect(); + // Verify each test case blob name appears in the list (with normalization) + for blob_name in test_cases { + let normalized_name = blob_name.replace('\\', "/"); + assert!( + listed_blob_names.contains(&normalized_name), + "Blob name '{}' (normalized: '{}') not found in list: {:?}", + blob_name, + normalized_name, + listed_blob_names + ); + } + + container_client.delete_container(None).await?; + + Ok(()) +} 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 35f860700f4..c9c55f6ab0b 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs @@ -98,13 +98,13 @@ async fn test_list_blobs(ctx: TestContext) -> Result<(), Box> { container_client.create_container(None).await?; create_test_blob( - &container_client.blob_client(blob_names[0].clone()), + &container_client.blob_client(&blob_names[0].clone()), None, None, ) .await?; create_test_blob( - &container_client.blob_client(blob_names[1].clone()), + &container_client.blob_client(&blob_names[1].clone()), None, None, ) @@ -143,25 +143,25 @@ async fn test_list_blobs_with_continuation(ctx: TestContext) -> Result<(), Box Result<(), Box Result<(), Box> { #[recorded::test] async fn test_find_blobs_by_tags_container(ctx: TestContext) -> Result<(), Box> { // Recording Setup - let recording = ctx.recording(); - recording.set_matcher(Matcher::HeaderlessMatcher).await?; - let container_client = get_container_client(recording, true).await?; + ctx.recording() + .set_matcher(Matcher::HeaderlessMatcher) + .await?; + let container_client = get_container_client(ctx.recording(), true).await?; // Create Test Blobs with Tags - let blob1_name = get_blob_name(recording); + let blob1_name = get_blob_name(ctx.recording()); create_test_blob( - &container_client.blob_client(blob1_name.clone()), + &container_client.blob_client(&blob1_name.clone()), Some(RequestContent::from("hello world".as_bytes().into())), Some( BlockBlobClientUploadOptions::default().with_tags(HashMap::from([ @@ -348,17 +349,19 @@ async fn test_find_blobs_by_tags_container(ctx: TestContext) -> Result<(), Box Result<(), Box> { ]); let mut container_clients = Vec::new(); for container_name in container_names.keys() { - let container_client = service_client.blob_container_client(container_name.to_string()); + let container_client = service_client.blob_container_client(&container_name.to_string()); container_client.create_container(None).await?; container_clients.push(container_client); } @@ -91,7 +91,7 @@ async fn test_list_containers_with_continuation(ctx: TestContext) -> Result<(), ]); let mut container_clients = Vec::new(); for container_name in container_names.keys() { - let container_client = service_client.blob_container_client(container_name.to_string()); + let container_client = service_client.blob_container_client(&container_name.to_string()); container_client.create_container(None).await?; container_clients.push(container_client); } @@ -184,7 +184,7 @@ async fn test_find_blobs_by_tags_service(ctx: TestContext) -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let block_blob_client = blob_client.block_blob_client(); let block_1 = b"AAA"; @@ -117,40 +117,28 @@ async fn test_upload_blob_from_url(ctx: TestContext) -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let page_blob_client = blob_client.page_blob_client(); // Regular Create Scenario @@ -59,7 +59,7 @@ async fn test_upload_page(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let page_blob_client = blob_client.page_blob_client(); page_blob_client.create(512, None).await?; let data = vec![b'A'; 512]; @@ -89,7 +89,7 @@ async fn test_clear_page(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let page_blob_client = blob_client.page_blob_client(); page_blob_client.create(512, None).await?; let data = vec![b'A'; 512]; @@ -123,7 +123,7 @@ async fn test_resize_blob(ctx: TestContext) -> Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let page_blob_client = blob_client.page_blob_client(); // Blob Too Small Scenario @@ -171,7 +171,7 @@ async fn test_set_sequence_number(ctx: TestContext) -> Result<(), Box let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let page_blob_client = blob_client.page_blob_client(); // Update Action @@ -216,8 +216,8 @@ async fn test_upload_page_from_url(ctx: TestContext) -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { // Recording Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); let page_blob_client = blob_client.page_blob_client(); page_blob_client.create(1024, None).await?; diff --git a/sdk/storage/azure_storage_blob/tests/streaming.rs b/sdk/storage/azure_storage_blob/tests/streaming.rs index ac409b3839b..92db8b2c850 100644 --- a/sdk/storage/azure_storage_blob/tests/streaming.rs +++ b/sdk/storage/azure_storage_blob/tests/streaming.rs @@ -14,7 +14,7 @@ async fn stream(ctx: TestContext) -> Result<(), Box> { // Setup let recording = ctx.recording(); let container_client = get_container_client(recording, true).await?; - let blob_client = container_client.blob_client(get_blob_name(recording)); + let blob_client = container_client.blob_client(&get_blob_name(recording)); // Upload from a stream. const CONTENT_LENGTH: usize = 40_960_000; diff --git a/sdk/storage/azure_storage_blob/tsp-location.yaml b/sdk/storage/azure_storage_blob/tsp-location.yaml index 2ba329c3415..2f51fc40613 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: cc4322ec468b171e696330258ea59c3b3f657104 +commit: 6b5a0fdadca03abe0b8e91a68a62cd1e639ed55e 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 46c30ad5096..48b88a6f9f0 100644 --- a/sdk/storage/azure_storage_blob_test/src/lib.rs +++ b/sdk/storage/azure_storage_blob_test/src/lib.rs @@ -17,7 +17,7 @@ use azure_storage_blob::{ /// # Arguments /// /// * `recording` - A reference to a Recording instance. -fn recorded_test_setup(recording: &Recording) -> (ClientOptions, String) { +pub fn recorded_test_setup(recording: &Recording) -> (ClientOptions, String) { let mut client_options = ClientOptions::default(); recording.instrument(&mut client_options); let endpoint = format!( @@ -63,7 +63,7 @@ pub fn get_blob_service_client(recording: &Recording) -> Result