sentry-cli 2.57.0__tar.gz → 2.58.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/Cargo.lock +1 -1
  2. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/Cargo.toml +1 -1
  3. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/PKG-INFO +1 -1
  4. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift +142 -10
  5. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/sentry_cli.egg-info/PKG-INFO +1 -1
  6. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/upload/capability.rs +4 -0
  7. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/upload/options.rs +3 -1
  8. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/build/mod.rs +2 -10
  9. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/build/upload.rs +11 -7
  10. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/dart_symbol_map/upload.rs +1 -1
  11. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/debug_files/bundle_jvm.rs +0 -1
  12. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/files/upload.rs +0 -1
  13. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/react_native/appcenter.rs +0 -2
  14. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/react_native/gradle.rs +0 -2
  15. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/react_native/xcode.rs +0 -3
  16. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/sourcemaps/upload.rs +9 -6
  17. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/upload_proguard.rs +26 -3
  18. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/build/mod.rs +1 -1
  19. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/build/normalize.rs +32 -3
  20. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/chunks/types.rs +7 -7
  21. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/dif_upload/mod.rs +3 -3
  22. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/file_upload.rs +3 -10
  23. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/fs.rs +11 -18
  24. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/proguard/upload.rs +3 -2
  25. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/releases.rs +2 -1
  26. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/sourcemaps.rs +1 -52
  27. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/vcs.rs +70 -48
  28. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/LICENSE +0 -0
  29. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/MANIFEST.in +0 -0
  30. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/README.md +0 -0
  31. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/Cargo.toml +0 -0
  32. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/build.rs +0 -0
  33. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Package.swift +0 -0
  34. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/ObjcSupport/include/safeValueForKey.h +0 -0
  35. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/ObjcSupport/safeValueForKey.m +0 -0
  36. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/AssetCatalogParserTests.swift +0 -0
  37. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/Resources/test.xcarchive/Info.plist +0 -0
  38. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/Resources/test.xcarchive/Products/Applications/DemoApp.app/Assets.car +0 -0
  39. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/src/asset_catalog.rs +0 -0
  40. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/apple-catalog-parsing/src/lib.rs +0 -0
  41. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/build.rs +0 -0
  42. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/pyproject.toml +0 -0
  43. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/sentry_cli.egg-info/SOURCES.txt +0 -0
  44. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/sentry_cli.egg-info/dependency_links.txt +0 -0
  45. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/sentry_cli.egg-info/top_level.txt +0 -0
  46. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/setup.cfg +0 -0
  47. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/setup.py +0 -0
  48. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/connection_manager.rs +0 -0
  49. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/artifact.rs +0 -0
  50. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/build.rs +0 -0
  51. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/compression.rs +0 -0
  52. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/dif.rs +0 -0
  53. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/file_state.rs +0 -0
  54. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/hash_algorithm.rs +0 -0
  55. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/mod.rs +0 -0
  56. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/chunking/upload/mod.rs +0 -0
  57. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/deploy.rs +0 -0
  58. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/data_types/mod.rs +0 -0
  59. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/encoding.rs +0 -0
  60. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/envelopes_api.rs +0 -0
  61. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/errors/api_error.rs +0 -0
  62. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/errors/mod.rs +0 -0
  63. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/errors/sentry_error.rs +0 -0
  64. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/mod.rs +0 -0
  65. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/api/pagination.rs +0 -0
  66. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/bashsupport.sh +0 -0
  67. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/bash_hook.rs +0 -0
  68. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/dart_symbol_map/mod.rs +0 -0
  69. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/debug_files/bundle_sources.rs +0 -0
  70. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/debug_files/check.rs +0 -0
  71. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/debug_files/find.rs +0 -0
  72. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/debug_files/mod.rs +0 -0
  73. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/debug_files/print_sources.rs +0 -0
  74. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/debug_files/upload.rs +0 -0
  75. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/deploys/list.rs +0 -0
  76. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/deploys/mod.rs +0 -0
  77. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/deploys/new.rs +0 -0
  78. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/derive_parser.rs +0 -0
  79. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/events/list.rs +0 -0
  80. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/events/mod.rs +0 -0
  81. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/files/delete.rs +0 -0
  82. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/files/list.rs +0 -0
  83. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/files/mod.rs +0 -0
  84. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/info.rs +0 -0
  85. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/issues/list.rs +0 -0
  86. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/issues/mod.rs +0 -0
  87. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/issues/mute.rs +0 -0
  88. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/issues/resolve.rs +0 -0
  89. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/issues/unresolve.rs +0 -0
  90. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/login.rs +0 -0
  91. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/logs/list.rs +0 -0
  92. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/logs/mod.rs +0 -0
  93. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/mod.rs +0 -0
  94. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/monitors/list.rs +0 -0
  95. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/monitors/mod.rs +0 -0
  96. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/monitors/run.rs +0 -0
  97. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/organizations/list.rs +0 -0
  98. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/organizations/mod.rs +0 -0
  99. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/projects/list.rs +0 -0
  100. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/projects/mod.rs +0 -0
  101. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/react_native/mod.rs +0 -0
  102. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/archive.rs +0 -0
  103. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/delete.rs +0 -0
  104. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/finalize.rs +0 -0
  105. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/info.rs +0 -0
  106. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/list.rs +0 -0
  107. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/mod.rs +0 -0
  108. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/new.rs +0 -0
  109. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/propose_version.rs +0 -0
  110. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/restore.rs +0 -0
  111. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/releases/set_commits.rs +0 -0
  112. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/repos/list.rs +0 -0
  113. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/repos/mod.rs +0 -0
  114. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/send_envelope.rs +0 -0
  115. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/send_event.rs +0 -0
  116. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/send_metric/common_args.rs +0 -0
  117. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/send_metric/distribution.rs +0 -0
  118. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/send_metric/gauge.rs +0 -0
  119. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/send_metric/increment.rs +0 -0
  120. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/send_metric/mod.rs +0 -0
  121. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/send_metric/set.rs +0 -0
  122. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/sourcemaps/explain.rs +0 -0
  123. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/sourcemaps/inject.rs +0 -0
  124. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/sourcemaps/mod.rs +0 -0
  125. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/sourcemaps/resolve.rs +0 -0
  126. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/uninstall.rs +0 -0
  127. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/update.rs +0 -0
  128. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/upload_dif.rs +0 -0
  129. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/commands/upload_dsym.rs +0 -0
  130. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/config.rs +0 -0
  131. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/constants.rs +0 -0
  132. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/main.rs +0 -0
  133. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/android.rs +0 -0
  134. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/appcenter.rs +0 -0
  135. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/args.rs +0 -0
  136. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/auth_token/auth_token_impl.rs +0 -0
  137. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/auth_token/error.rs +0 -0
  138. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/auth_token/mod.rs +0 -0
  139. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/auth_token/org_auth_token.rs +0 -0
  140. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/auth_token/redacting.rs +0 -0
  141. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/auth_token/test.rs +0 -0
  142. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/auth_token/user_auth_token.rs +0 -0
  143. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/build/apple.rs +0 -0
  144. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/build/validation.rs +0 -0
  145. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/chunks/mod.rs +0 -0
  146. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/chunks/options.rs +0 -0
  147. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/chunks/upload.rs +0 -0
  148. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/cordova.rs +0 -0
  149. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/dif.rs +0 -0
  150. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/dif_upload/error.rs +0 -0
  151. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/event.rs +0 -0
  152. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/file_search.rs +0 -0
  153. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/formatting.rs +0 -0
  154. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/http.rs +0 -0
  155. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/logging.rs +0 -0
  156. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/metrics.rs +0 -0
  157. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/mod.rs +0 -0
  158. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/non_empty.rs +0 -0
  159. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/progress.rs +0 -0
  160. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/proguard/mapping.rs +0 -0
  161. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/proguard/mod.rs +0 -0
  162. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/retry.rs +0 -0
  163. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__generate_patch_default_twenty.snap +0 -0
  164. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__generate_patch_ignore_missing.snap +0 -0
  165. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__generate_patch_set_base.snap +0 -0
  166. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__generate_patch_set_previous_commit.snap +0 -0
  167. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__get_commits_from_git.snap +0 -0
  168. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/sourcemaps/inject.rs +0 -0
  169. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/system.rs +0 -0
  170. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/ui.rs +0 -0
  171. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/update.rs +0 -0
  172. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/value_parsers.rs +0 -0
  173. {sentry_cli-2.57.0 → sentry_cli-2.58.0}/src/utils/xcode.rs +0 -0
@@ -2726,7 +2726,7 @@ dependencies = [
2726
2726
 
2727
2727
  [[package]]
2728
2728
  name = "sentry-cli"
2729
- version = "2.57.0"
2729
+ version = "2.58.0"
2730
2730
  dependencies = [
2731
2731
  "anyhow",
2732
2732
  "anylog",
@@ -2,7 +2,7 @@
2
2
  authors = ["Armin Ronacher <armin.ronacher@active-4.com>"]
3
3
  build = "build.rs"
4
4
  name = "sentry-cli"
5
- version = "2.57.0"
5
+ version = "2.58.0"
6
6
  edition = "2021"
7
7
  rust-version = "1.86"
8
8
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sentry_cli
3
- Version: 2.57.0
3
+ Version: 2.58.0
4
4
  Summary: A command line utility to work with Sentry.
5
5
  Home-page: https://github.com/getsentry/sentry-cli
6
6
  Author: Sentry
@@ -38,6 +38,8 @@ struct AssetCatalogEntry: Encodable {
38
38
  let height: Int?
39
39
  let filename: String?
40
40
  let type: AssetType?
41
+ let idiom: String?
42
+ let colorspace: String?
41
43
  }
42
44
 
43
45
  enum Error: Swift.Error {
@@ -48,7 +50,40 @@ typealias objectiveCMethodImp = @convention(c) (AnyObject, Selector, UnsafeRawPo
48
50
  AnyObject
49
51
  >?
50
52
 
53
+ private struct MultisizeSetInfo {
54
+ let name: String
55
+ let element: UInt
56
+ let part: UInt
57
+ let identifier: UInt
58
+ let sizeIndexes: [(idiom: UInt, subtype: UInt)]
59
+ }
60
+
51
61
  enum AssetUtil {
62
+ private static func idiomToString(_ idiom: UInt?) -> String? {
63
+ guard let idiom = idiom else { return nil }
64
+ switch idiom {
65
+ case 0: return "universal"
66
+ case 1: return "phone"
67
+ case 2: return "pad"
68
+ case 3: return "tv"
69
+ case 4: return "carplay"
70
+ case 5: return "watch"
71
+ case 6: return "marketing"
72
+ default: return nil
73
+ }
74
+ }
75
+
76
+ private static func colorSpaceIDToString(_ colorSpaceID: UInt?) -> String? {
77
+ guard let colorSpaceID = colorSpaceID else { return nil }
78
+ switch colorSpaceID {
79
+ case 1: return "srgb"
80
+ case 2: return "gray gamma 22"
81
+ case 3: return "displayP3"
82
+ case 4: return "extended srgb"
83
+ default: return nil
84
+ }
85
+ }
86
+
52
87
  private static func createResultsPath(assetURL: URL, outputURL: URL) throws -> URL {
53
88
  var archiveURL = assetURL
54
89
  var tailComponents: [String] = []
@@ -78,8 +113,12 @@ enum AssetUtil {
78
113
  let (structuredThemeStore, assetKeys) = initializeCatalog(from: file)
79
114
 
80
115
  var images: [String: (cgImage: CGImage, format: String)] = [:]
81
-
82
- for key in assetKeys {
116
+
117
+ // First pass: Build map of multisize sets and cache renditions for performance
118
+ var multisizeSets: [MultisizeSetInfo] = []
119
+ var renditionCache: [Int: NSObject] = [:]
120
+
121
+ for (index, key) in assetKeys.enumerated() {
83
122
  let keyList = unsafeBitCast(
84
123
  key.perform(Selector(("keyList"))),
85
124
  to: UnsafeMutableRawPointer.self
@@ -87,6 +126,49 @@ enum AssetUtil {
87
126
  guard let rendition = createRendition(from: structuredThemeStore, keyList) else {
88
127
  continue
89
128
  }
129
+ renditionCache[index] = rendition
130
+
131
+ let type = rendition.getUInt(forKey: "type") ?? 0
132
+ if type == 1010 { // Multisize image set
133
+ let renditionTypeName = rendition.perform(Selector(("name"))).takeUnretainedValue() as! String
134
+ let keyElement = key.getUInt(forKey: "themeElement") ?? 0
135
+ let keyPart = key.getUInt(forKey: "themePart") ?? 0
136
+ let keyIdentifier = key.getUInt(forKey: "themeIdentifier") ?? 0
137
+
138
+ // Extract size indexes to identify which images belong to this set
139
+ var sizeIndexes: [(idiom: UInt, subtype: UInt)] = []
140
+ if rendition.responds(to: Selector(("sizeIndexes"))),
141
+ let sizeIndexesResult = rendition.perform(Selector(("sizeIndexes"))),
142
+ let sizeIndexesArray = sizeIndexesResult.takeUnretainedValue() as? NSArray {
143
+ for sizeIndexObj in sizeIndexesArray {
144
+ if let obj = sizeIndexObj as? NSObject {
145
+ let idiom = obj.getUInt(forKey: "idiom") ?? 0
146
+ let subtype = obj.getUInt(forKey: "subtype") ?? 0
147
+ sizeIndexes.append((idiom: idiom, subtype: subtype))
148
+ }
149
+ }
150
+ }
151
+
152
+ multisizeSets.append(MultisizeSetInfo(
153
+ name: renditionTypeName,
154
+ element: keyElement,
155
+ part: keyPart,
156
+ identifier: keyIdentifier,
157
+ sizeIndexes: sizeIndexes
158
+ ))
159
+ }
160
+ }
161
+
162
+ // Second pass: Process all assets using cached renditions
163
+ for (index, key) in assetKeys.enumerated() {
164
+ guard let rendition = renditionCache[index] else {
165
+ continue
166
+ }
167
+
168
+ let keyList = unsafeBitCast(
169
+ key.perform(Selector(("keyList"))),
170
+ to: UnsafeMutableRawPointer.self
171
+ )
90
172
 
91
173
  let data = rendition.value(forKey: "_srcData") as! Data
92
174
  let length = UInt(data.count)
@@ -126,26 +208,50 @@ enum AssetUtil {
126
208
  let type = rendition.getUInt(forKey: "type") ?? 0
127
209
 
128
210
  let isVector = type == 9
129
- let (width, height, unslicedImage) = resolveImageDimensions(rendition, isVector)
211
+ let isMultisizeImageSet = type == 1010
130
212
  let assetType = determineAssetType(key)
131
213
  let imageId = UUID().uuidString
132
-
133
214
  let fileExtension = (renditionTypeName as NSString).pathExtension.lowercased()
134
215
 
135
- // Skip files without an extension or SVGs
136
- if !fileExtension.isEmpty && fileExtension != "svg", let unslicedImage = unslicedImage {
137
- images[imageId] = (cgImage: unslicedImage, format: fileExtension)
216
+ var width: Int?
217
+ var height: Int?
218
+ var unslicedImage: CGImage?
219
+
220
+ if isMultisizeImageSet {
221
+ continue
222
+ } else {
223
+ // Get image dimensions from regular rendition
224
+ (width, height, unslicedImage) = resolveImageDimensions(rendition, isVector)
225
+
226
+ // Skip SVGs, but save images even if they don't have an extension (default to png)
227
+ if fileExtension != "svg", let unslicedImage = unslicedImage {
228
+ let format = fileExtension.isEmpty ? "png" : fileExtension
229
+ images[imageId] = (cgImage: unslicedImage, format: format)
230
+ }
231
+ }
232
+
233
+ let idiomValue = key.getUInt(forKey: "themeIdiom")
234
+ let colorSpaceID = rendition.getUInt(forKey: "colorSpaceID")
235
+
236
+ // Include multisize set name in the name field if it exists
237
+ let finalName: String
238
+ if let setName = findMultisizeSetName(key, in: multisizeSets) {
239
+ finalName = "\(setName)/\(name)"
240
+ } else {
241
+ finalName = name
138
242
  }
139
243
 
140
244
  let asset = AssetCatalogEntry(
141
245
  imageId: imageId,
142
246
  size: length,
143
- name: name,
247
+ name: finalName,
144
248
  vector: isVector,
145
249
  width: width,
146
250
  height: height,
147
251
  filename: renditionTypeName,
148
- type: assetType
252
+ type: assetType,
253
+ idiom: idiomToString(idiomValue),
254
+ colorspace: colorSpaceIDToString(colorSpaceID)
149
255
  )
150
256
  assets.append(asset)
151
257
  }
@@ -158,7 +264,9 @@ enum AssetUtil {
158
264
  width: nil,
159
265
  height: nil,
160
266
  filename: nil,
161
- type: nil
267
+ type: nil,
268
+ idiom: nil,
269
+ colorspace: nil
162
270
  ))
163
271
 
164
272
  let data = try! JSONEncoder().encode(assets)
@@ -254,6 +362,30 @@ enum AssetUtil {
254
362
  }
255
363
  return .image
256
364
  }
365
+
366
+ private static func findMultisizeSetName(
367
+ _ key: NSObject,
368
+ in multisizeSets: [MultisizeSetInfo]
369
+ ) -> String? {
370
+ let element = key.getUInt(forKey: "themeElement") ?? 0
371
+ let identifier = key.getUInt(forKey: "themeIdentifier") ?? 0
372
+ let idiom = key.getUInt(forKey: "themeIdiom") ?? 0
373
+ let subtype = key.getUInt(forKey: "themeSubtype") ?? 0
374
+
375
+ for setInfo in multisizeSets {
376
+ guard setInfo.element == element,
377
+ setInfo.identifier == identifier else {
378
+ continue
379
+ }
380
+
381
+ for sizeIndex in setInfo.sizeIndexes {
382
+ if sizeIndex.idiom == idiom && sizeIndex.subtype == subtype {
383
+ return setInfo.name
384
+ }
385
+ }
386
+ }
387
+ return nil
388
+ }
257
389
 
258
390
  private static func resolveRenditionName(
259
391
  _ structuredThemeStore: NSObject,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sentry_cli
3
- Version: 2.57.0
3
+ Version: 2.58.0
4
4
  Summary: A command line utility to work with Sentry.
5
5
  Home-page: https://github.com/getsentry/sentry-cli
6
6
  Author: Sentry
@@ -36,6 +36,9 @@ pub enum ChunkUploadCapability {
36
36
  /// Upload of preprod artifacts
37
37
  PreprodArtifacts,
38
38
 
39
+ /// Upload of ProGuard mappings
40
+ Proguard,
41
+
39
42
  /// Any other unsupported capability (ignored)
40
43
  Unknown,
41
44
  }
@@ -57,6 +60,7 @@ impl<'de> Deserialize<'de> for ChunkUploadCapability {
57
60
  "il2cpp" => ChunkUploadCapability::Il2Cpp,
58
61
  "dartsymbolmap" => ChunkUploadCapability::DartSymbolMap,
59
62
  "preprod_artifacts" => ChunkUploadCapability::PreprodArtifacts,
63
+ "proguard" => ChunkUploadCapability::Proguard,
60
64
  _ => ChunkUploadCapability::Unknown,
61
65
  })
62
66
  }
@@ -1,3 +1,5 @@
1
+ use std::num::NonZeroUsize;
2
+
1
3
  use serde::Deserialize;
2
4
 
3
5
  use super::{ChunkCompression, ChunkHashAlgorithm, ChunkUploadCapability};
@@ -17,7 +19,7 @@ pub struct ChunkServerOptions {
17
19
  pub max_wait: u64,
18
20
  #[expect(dead_code)]
19
21
  pub hash_algorithm: ChunkHashAlgorithm,
20
- pub chunk_size: u64,
22
+ pub chunk_size: NonZeroUsize,
21
23
  pub concurrency: u8,
22
24
  #[serde(default)]
23
25
  pub compression: Vec<ChunkCompression>,
@@ -21,24 +21,16 @@ pub fn make_command(mut command: Command) -> Command {
21
21
  }
22
22
 
23
23
  command = command
24
- .about("[EXPERIMENTAL] Manage builds.")
24
+ .about("Manage builds.")
25
25
  .subcommand_required(true)
26
26
  .arg_required_else_help(true)
27
27
  .org_arg()
28
- .project_arg(true)
29
- // TODO: Remove this when ready for release
30
- .hide(true);
28
+ .project_arg(true);
31
29
  each_subcommand!(add_subcommand);
32
30
  command
33
31
  }
34
32
 
35
33
  pub fn execute(matches: &ArgMatches) -> Result<()> {
36
- log::warn!(
37
- "EXPERIMENTAL: The build subcommand is experimental. \
38
- The command is subject to breaking changes and may be removed \
39
- without notice in any release."
40
- );
41
-
42
34
  macro_rules! execute_subcommand {
43
35
  ($name:ident) => {{
44
36
  if let Some(sub_matches) =
@@ -17,7 +17,9 @@ use crate::config::Config;
17
17
  use crate::utils::args::ArgExt as _;
18
18
  #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
19
19
  use crate::utils::build::{handle_asset_catalogs, ipa_to_xcarchive, is_apple_app, is_ipa_file};
20
- use crate::utils::build::{is_aab_file, is_apk_file, is_zip_file, normalize_directory};
20
+ use crate::utils::build::{
21
+ is_aab_file, is_apk_file, is_zip_file, normalize_directory, write_version_metadata,
22
+ };
21
23
  use crate::utils::chunks::{upload_chunks, Chunk};
22
24
  use crate::utils::fs::get_sha1_checksums;
23
25
  use crate::utils::fs::TempDir;
@@ -37,7 +39,7 @@ pub fn make_command(command: Command) -> Command {
37
39
  const HELP_TEXT: &str =
38
40
  "The path to the build to upload. Supported files include Apk, and Aab.";
39
41
  command
40
- .about("[EXPERIMENTAL] Upload builds to a project.")
42
+ .about("Upload builds to a project.")
41
43
  .org_arg()
42
44
  .project_arg(false)
43
45
  .arg(
@@ -113,7 +115,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
113
115
  .get_one("head_sha")
114
116
  .map(String::as_str)
115
117
  .map(Cow::Borrowed)
116
- .or_else(|| vcs::find_head().ok().map(Cow::Owned));
118
+ .or_else(|| vcs::find_head_sha().ok().map(Cow::Owned));
117
119
 
118
120
  let cached_remote = config.get_cached_vcs_remote();
119
121
  // Try to open the git repository and find the remote, but handle errors gracefully.
@@ -233,7 +235,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
233
235
  .map(String::as_str)
234
236
  .map(Cow::Borrowed)
235
237
  .or_else(|| {
236
- vcs::find_base_sha()
238
+ vcs::find_base_sha(&cached_remote)
237
239
  .inspect_err(|e| debug!("Error finding base SHA: {e}"))
238
240
  .ok()
239
241
  .flatten()
@@ -455,6 +457,8 @@ fn normalize_file(path: &Path, bytes: &[u8]) -> Result<TempFile> {
455
457
  zip.start_file(file_name, options)?;
456
458
  zip.write_all(bytes)?;
457
459
 
460
+ write_version_metadata(&mut zip)?;
461
+
458
462
  zip.finish()?;
459
463
  debug!("Successfully created normalized zip for file");
460
464
  Ok(temp_file)
@@ -507,10 +511,10 @@ fn upload_file(
507
511
  pb.enable_steady_tick(100);
508
512
  pb.set_style(progress_style);
509
513
 
510
- let chunk_size = chunk_upload_options.chunk_size as usize;
511
- let (checksum, checksums) = get_sha1_checksums(bytes, chunk_size)?;
514
+ let chunk_size = chunk_upload_options.chunk_size;
515
+ let (checksum, checksums) = get_sha1_checksums(bytes, chunk_size);
512
516
  let mut chunks = bytes
513
- .chunks(chunk_size)
517
+ .chunks(chunk_size.into())
514
518
  .zip(checksums.iter())
515
519
  .map(|(data, checksum)| Chunk((*checksum, data)))
516
520
  .collect::<Vec<_>>();
@@ -159,7 +159,7 @@ pub(super) fn execute(args: DartSymbolMapUploadArgs) -> Result<()> {
159
159
  let options = ChunkOptions::new(chunk_upload_options, org, project)
160
160
  .with_max_wait(DEFAULT_MAX_WAIT);
161
161
 
162
- let chunked = Chunked::from(object, options.server_options().chunk_size as usize)?;
162
+ let chunked = Chunked::from(object, options.server_options().chunk_size);
163
163
  let (_uploaded, has_processing_errors) = upload_chunked_objects(&[chunked], options)?;
164
164
  if has_processing_errors {
165
165
  bail!("Some symbol maps did not process correctly");
@@ -65,7 +65,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
65
65
  note: None,
66
66
  wait: true,
67
67
  max_wait: DEFAULT_MAX_WAIT,
68
- dedupe: false,
69
68
  chunk_upload_options: chunk_upload_options.as_ref(),
70
69
  };
71
70
  let path = matches.get_one::<PathBuf>("path").unwrap();
@@ -159,7 +159,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
159
159
  note: None,
160
160
  wait,
161
161
  max_wait,
162
- dedupe: false,
163
162
  chunk_upload_options: chunk_upload_options.as_ref(),
164
163
  };
165
164
 
@@ -202,7 +202,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
202
202
  note: None,
203
203
  wait,
204
204
  max_wait,
205
- dedupe: false,
206
205
  chunk_upload_options: chunk_upload_options.as_ref(),
207
206
  })?;
208
207
  }
@@ -221,7 +220,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
221
220
  note: None,
222
221
  wait,
223
222
  max_wait,
224
- dedupe: false,
225
223
  chunk_upload_options: chunk_upload_options.as_ref(),
226
224
  })?;
227
225
  }
@@ -129,7 +129,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
129
129
  note: None,
130
130
  wait,
131
131
  max_wait,
132
- dedupe: false,
133
132
  chunk_upload_options: chunk_upload_options.as_ref(),
134
133
  })?;
135
134
  }
@@ -143,7 +142,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
143
142
  note: None,
144
143
  wait,
145
144
  max_wait,
146
- dedupe: false,
147
145
  chunk_upload_options: chunk_upload_options.as_ref(),
148
146
  })?;
149
147
  }
@@ -351,7 +351,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
351
351
  note: None,
352
352
  wait,
353
353
  max_wait,
354
- dedupe: false,
355
354
  chunk_upload_options: chunk_upload_options.as_ref(),
356
355
  })?;
357
356
  } else {
@@ -387,7 +386,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
387
386
  note: None,
388
387
  wait,
389
388
  max_wait,
390
- dedupe: false,
391
389
  chunk_upload_options: chunk_upload_options.as_ref(),
392
390
  })?;
393
391
  }
@@ -401,7 +399,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
401
399
  note: None,
402
400
  wait,
403
401
  max_wait,
404
- dedupe: false,
405
402
  chunk_upload_options: chunk_upload_options.as_ref(),
406
403
  })?;
407
404
  }
@@ -193,11 +193,8 @@ pub fn make_command(command: Command) -> Command {
193
193
  Arg::new("no_dedupe")
194
194
  .long("no-dedupe")
195
195
  .action(ArgAction::SetTrue)
196
- .help(
197
- "Skip artifacts deduplication prior to uploading. \
198
- This will force all artifacts to be uploaded, \
199
- no matter whether they are already present on the server.",
200
- ),
196
+ .hide(true)
197
+ .help("[DEPRECATED] This flag has no effect and is scheduled for removal."),
201
198
  )
202
199
  .arg(
203
200
  Arg::new("extensions")
@@ -419,6 +416,13 @@ fn process_sources_from_paths(
419
416
  }
420
417
 
421
418
  pub fn execute(matches: &ArgMatches) -> Result<()> {
419
+ if matches.get_flag("no_dedupe") {
420
+ log::warn!(
421
+ "[DEPRECATION NOTICE] The --no-dedupe flag is deprecated and has no \
422
+ effect. It will be removed in the next major version."
423
+ );
424
+ }
425
+
422
426
  let config = Config::current();
423
427
  let version = config.get_release_with_legacy_fallback(matches).ok();
424
428
  let org = config.get_org(matches)?;
@@ -457,7 +461,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
457
461
  note: matches.get_one::<String>("note").map(String::as_str),
458
462
  wait,
459
463
  max_wait,
460
- dedupe: !matches.get_flag("no_dedupe"),
461
464
  chunk_upload_options: chunk_upload_options.as_ref(),
462
465
  };
463
466
 
@@ -85,12 +85,13 @@ pub fn make_command(command: Command) -> Command {
85
85
  )
86
86
  .arg(
87
87
  Arg::new("platform")
88
+ .hide(true)
88
89
  .long("platform")
89
90
  .value_name("PLATFORM")
90
91
  .requires("app_id")
91
92
  .help(
92
- "Optionally defines the platform for the app association. \
93
- [defaults to 'android']",
93
+ "[DEPRECATED] This flag is a no-op, scheduled \
94
+ for removal in Sentry CLI 3.0.0.",
94
95
  ),
95
96
  )
96
97
  .arg(
@@ -110,7 +111,10 @@ pub fn make_command(command: Command) -> Command {
110
111
  .value_name("PATH")
111
112
  .conflicts_with("app_id")
112
113
  .hide(true)
113
- .help("Read version and version code from an Android manifest file."),
114
+ .help(
115
+ "[DEPRECATED] This flag is a no-op, scheduled \
116
+ for removal in Sentry CLI 3.0.0.",
117
+ ),
114
118
  )
115
119
  .arg(
116
120
  Arg::new("write_properties")
@@ -145,6 +149,22 @@ pub fn make_command(command: Command) -> Command {
145
149
  }
146
150
 
147
151
  pub fn execute(matches: &ArgMatches) -> Result<()> {
152
+ if matches.get_one::<String>("platform").is_some() {
153
+ log::warn!(
154
+ "[DEPRECATION NOTICE] The --platform argument is deprecated, \
155
+ and is scheduled for removal in Sentry CLI 3.0.0. \
156
+ The argument is a no-op."
157
+ );
158
+ }
159
+
160
+ if matches.get_one::<String>("android_manifest").is_some() {
161
+ log::warn!(
162
+ "[DEPRECATION NOTICE] The --android-manifest argument is deprecated, \
163
+ and is scheduled for removal in Sentry CLI 3.0.0. \
164
+ The argument is a no-op."
165
+ );
166
+ }
167
+
148
168
  let paths: Vec<_> = match matches.get_many::<String>("paths") {
149
169
  Some(paths) => paths.collect(),
150
170
  None => {
@@ -194,6 +214,9 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
194
214
  }
195
215
  }
196
216
 
217
+ // We are done constructing the mappings, redeclare as immutable.
218
+ let mappings = mappings;
219
+
197
220
  let api = Api::current();
198
221
  let config = Config::current();
199
222
 
@@ -5,7 +5,7 @@ mod validation;
5
5
 
6
6
  #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
7
7
  pub use self::apple::{handle_asset_catalogs, ipa_to_xcarchive};
8
- pub use self::normalize::normalize_directory;
8
+ pub use self::normalize::{normalize_directory, write_version_metadata};
9
9
  pub use self::validation::{is_aab_file, is_apk_file, is_zip_file};
10
10
  #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
11
11
  pub use self::validation::{is_apple_app, is_ipa_file};
@@ -1,3 +1,4 @@
1
+ use std::borrow::Cow;
1
2
  #[cfg(not(windows))]
2
3
  use std::fs;
3
4
  use std::fs::File;
@@ -6,8 +7,9 @@ use std::io::Write as _;
6
7
  use std::os::unix::fs::PermissionsExt as _;
7
8
  use std::path::{Path, PathBuf};
8
9
 
10
+ use crate::constants::VERSION;
9
11
  use crate::utils::fs::TempFile;
10
- use anyhow::Result;
12
+ use anyhow::{Context as _, Result};
11
13
  use itertools::Itertools as _;
12
14
  use log::debug;
13
15
  use symbolic::common::ByteView;
@@ -15,6 +17,14 @@ use walkdir::WalkDir;
15
17
  use zip::write::SimpleFileOptions;
16
18
  use zip::{DateTime, ZipWriter};
17
19
 
20
+ fn get_version() -> Cow<'static, str> {
21
+ // Integration tests can override the version for consistent test results.
22
+ // This ensures deterministic checksums in test fixtures by using a fixed version.
23
+ std::env::var("SENTRY_CLI_INTEGRATION_TEST_VERSION_OVERRIDE")
24
+ .map(Cow::Owned)
25
+ .unwrap_or(Cow::Borrowed(VERSION))
26
+ }
27
+
18
28
  fn sort_entries(path: &Path) -> Result<impl Iterator<Item = (PathBuf, PathBuf)>> {
19
29
  Ok(WalkDir::new(path)
20
30
  .into_iter()
@@ -61,10 +71,12 @@ fn add_entries_to_zip(
61
71
  let target_str = target.to_string_lossy();
62
72
 
63
73
  // Create a symlink entry in the zip
64
- zip.add_symlink(zip_path, &target_str, options)?;
74
+ zip.add_symlink(zip_path.as_str(), &target_str, options)
75
+ .with_context(|| format!("Failed to add symlink '{zip_path}' to zip archive"))?;
65
76
  } else {
66
77
  // Handle regular files
67
- zip.start_file(zip_path, options)?;
78
+ zip.start_file(zip_path.as_str(), options)
79
+ .with_context(|| format!("Failed to add file '{zip_path}' to zip archive"))?;
68
80
  let file_byteview = ByteView::open(&entry_path)?;
69
81
  zip.write_all(file_byteview.as_slice())?;
70
82
  }
@@ -74,6 +86,21 @@ fn add_entries_to_zip(
74
86
  Ok(file_count)
75
87
  }
76
88
 
89
+ fn metadata_file_options() -> SimpleFileOptions {
90
+ SimpleFileOptions::default()
91
+ .compression_method(zip::CompressionMethod::Deflated)
92
+ .last_modified_time(DateTime::default())
93
+ }
94
+
95
+ pub fn write_version_metadata<W: std::io::Write + std::io::Seek>(
96
+ zip: &mut ZipWriter<W>,
97
+ ) -> Result<()> {
98
+ let version = get_version();
99
+ zip.start_file(".sentry-cli-metadata.txt", metadata_file_options())?;
100
+ writeln!(zip, "sentry-cli-version: {version}")?;
101
+ Ok(())
102
+ }
103
+
77
104
  // For XCArchive directories, we'll zip the entire directory
78
105
  // It's important to not change the contents of the directory or the size
79
106
  // analysis will be wrong and the code signature will break.
@@ -106,6 +133,8 @@ pub fn normalize_directory(path: &Path, parsed_assets_path: &Path) -> Result<Tem
106
133
  )?;
107
134
  }
108
135
 
136
+ write_version_metadata(&mut zip)?;
137
+
109
138
  zip.finish()?;
110
139
  debug!("Successfully created normalized zip for directory with {file_count} files");
111
140
  Ok(temp_file)