sentry-cli 2.46.0__tar.gz → 2.47.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.
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/Cargo.lock +10 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/Cargo.toml +18 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/MANIFEST.in +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/PKG-INFO +2 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/README.md +1 -1
- sentry_cli-2.47.0/apple-catalog-parsing/Cargo.toml +10 -0
- sentry_cli-2.47.0/apple-catalog-parsing/build.rs +81 -0
- sentry_cli-2.47.0/apple-catalog-parsing/native/swift/AssetCatalogParser/Package.swift +33 -0
- sentry_cli-2.47.0/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift +301 -0
- sentry_cli-2.47.0/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/ObjcSupport/include/safeValueForKey.h +10 -0
- sentry_cli-2.47.0/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/ObjcSupport/safeValueForKey.m +11 -0
- sentry_cli-2.47.0/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/AssetCatalogParserTests.swift +12 -0
- sentry_cli-2.47.0/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/Resources/test.xcarchive/Info.plist +33 -0
- sentry_cli-2.47.0/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/Resources/test.xcarchive/Products/Applications/DemoApp.app/Assets.car +0 -0
- sentry_cli-2.47.0/apple-catalog-parsing/src/asset_catalog.rs +36 -0
- sentry_cli-2.47.0/apple-catalog-parsing/src/lib.rs +5 -0
- sentry_cli-2.47.0/build.rs +33 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/sentry_cli.egg-info/PKG-INFO +2 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/sentry_cli.egg-info/SOURCES.txt +17 -0
- sentry_cli-2.47.0/src/api/data_types/chunking/mobile_app.rs +23 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/mod.rs +3 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/upload/capability.rs +4 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/mod.rs +29 -3
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/bash_hook.rs +4 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/debug_files/bundle_jvm.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/debug_files/bundle_sources.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/debug_files/check.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/debug_files/find.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/debug_files/print_sources.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/deploys/list.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/deploys/new.rs +5 -3
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/events/list.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/files/upload.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/issues/list.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/login.rs +60 -4
- sentry_cli-2.47.0/src/commands/mobile_app/mod.rs +49 -0
- sentry_cli-2.47.0/src/commands/mobile_app/upload.rs +404 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/mod.rs +3 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/monitors/run.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/react_native/appcenter.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/react_native/gradle.rs +3 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/react_native/xcode.rs +3 -1
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/archive.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/delete.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/finalize.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/info.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/new.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/restore.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/set_commits.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/send_envelope.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/send_event.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/sourcemaps/explain.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/sourcemaps/inject.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/sourcemaps/resolve.rs +2 -7
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/sourcemaps/upload.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/upload_proguard.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/config.rs +2 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/main.rs +0 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/args.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/auth_token/org_auth_token.rs +0 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/auth_token/redacting.rs +1 -1
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/auth_token/user_auth_token.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/dif_upload/error.rs +1 -1
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/dif_upload/mod.rs +3 -1
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/event.rs +1 -1
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/file_search.rs +3 -4
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/file_upload.rs +2 -2
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/formatting.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/http.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/logging.rs +0 -24
- sentry_cli-2.47.0/src/utils/mobile_app/apple.rs +29 -0
- sentry_cli-2.47.0/src/utils/mobile_app/mod.rs +9 -0
- sentry_cli-2.47.0/src/utils/mobile_app/validation.rs +56 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/mod.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/releases.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/sourcemaps/inject.rs +1 -1
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/sourcemaps.rs +5 -3
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/system.rs +5 -6
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/ui.rs +1 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/update.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/vcs.rs +2 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/xcode.rs +2 -0
- sentry_cli-2.46.0/build.rs +0 -30
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/LICENSE +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/pyproject.toml +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/sentry_cli.egg-info/dependency_links.txt +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/sentry_cli.egg-info/top_level.txt +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/setup.cfg +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/setup.py +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/connection_manager.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/artifact.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/compression.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/dif.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/file_state.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/hash_algorithm.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/upload/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/chunking/upload/options.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/deploy.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/data_types/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/encoding.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/envelopes_api.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/errors/api_error.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/errors/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/errors/sentry_error.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/api/pagination.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/bashsupport.sh +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/debug_files/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/debug_files/upload.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/deploys/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/derive_parser.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/events/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/files/delete.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/files/list.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/files/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/info.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/issues/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/issues/mute.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/issues/resolve.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/issues/unresolve.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/monitors/list.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/monitors/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/organizations/list.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/organizations/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/projects/list.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/projects/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/react_native/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/list.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/releases/propose_version.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/repos/list.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/repos/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/send_metric/common_args.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/send_metric/distribution.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/send_metric/gauge.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/send_metric/increment.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/send_metric/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/send_metric/set.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/sourcemaps/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/uninstall.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/update.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/upload_dif.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/commands/upload_dsym.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/constants.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/android.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/appcenter.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/auth_token/auth_token_impl.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/auth_token/error.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/auth_token/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/auth_token/test.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/chunks/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/chunks/options.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/chunks/types.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/chunks/upload.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/cordova.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/dif.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/fs.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/metrics.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/progress.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/proguard/mapping.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/proguard/mod.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/proguard/upload.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/retry.rs +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/snapshots/sentry_cli__utils__vcs__generate_patch_default_twenty.snap +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/snapshots/sentry_cli__utils__vcs__generate_patch_ignore_missing.snap +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/snapshots/sentry_cli__utils__vcs__generate_patch_set_base.snap +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/snapshots/sentry_cli__utils__vcs__generate_patch_set_previous_commit.snap +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/snapshots/sentry_cli__utils__vcs__get_commits_from_git.snap +0 -0
- {sentry_cli-2.46.0 → sentry_cli-2.47.0}/src/utils/value_parsers.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This file is automatically @generated by Cargo.
|
|
2
2
|
# It is not intended for manual editing.
|
|
3
|
-
version =
|
|
3
|
+
version = 4
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "addr2line"
|
|
@@ -144,6 +144,13 @@ dependencies = [
|
|
|
144
144
|
"regex",
|
|
145
145
|
]
|
|
146
146
|
|
|
147
|
+
[[package]]
|
|
148
|
+
name = "apple-catalog-parsing"
|
|
149
|
+
version = "0.0.0"
|
|
150
|
+
dependencies = [
|
|
151
|
+
"thiserror 2.0.12",
|
|
152
|
+
]
|
|
153
|
+
|
|
147
154
|
[[package]]
|
|
148
155
|
name = "arbitrary"
|
|
149
156
|
version = "1.4.1"
|
|
@@ -2685,10 +2692,11 @@ dependencies = [
|
|
|
2685
2692
|
|
|
2686
2693
|
[[package]]
|
|
2687
2694
|
name = "sentry-cli"
|
|
2688
|
-
version = "2.
|
|
2695
|
+
version = "2.47.0"
|
|
2689
2696
|
dependencies = [
|
|
2690
2697
|
"anyhow",
|
|
2691
2698
|
"anylog",
|
|
2699
|
+
"apple-catalog-parsing",
|
|
2692
2700
|
"assert_cmd",
|
|
2693
2701
|
"backoff",
|
|
2694
2702
|
"brotli2",
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
authors = ["Armin Ronacher <armin.ronacher@active-4.com>"]
|
|
3
3
|
build = "build.rs"
|
|
4
4
|
name = "sentry-cli"
|
|
5
|
-
version = "2.
|
|
5
|
+
version = "2.47.0"
|
|
6
6
|
edition = "2021"
|
|
7
|
-
rust-version = "1.
|
|
7
|
+
rust-version = "1.86"
|
|
8
|
+
|
|
9
|
+
[workspace]
|
|
8
10
|
|
|
9
11
|
[dependencies]
|
|
10
12
|
anylog = "0.6.3"
|
|
11
13
|
anyhow = { version = "1.0.69", features = ["backtrace"] }
|
|
14
|
+
apple-catalog-parsing = { path = "apple-catalog-parsing", optional = true }
|
|
12
15
|
backoff = "0.4.0"
|
|
13
16
|
brotli2 = "0.3.2"
|
|
14
17
|
bytecount = "0.6.3"
|
|
@@ -91,12 +94,25 @@ default = []
|
|
|
91
94
|
managed = []
|
|
92
95
|
with_crash_reporting = []
|
|
93
96
|
|
|
97
|
+
# Feature flag for the mobile-app command, as it is still under development.
|
|
98
|
+
# CI tests run against this flag, but we don't include it in release builds.
|
|
99
|
+
unstable-mobile-app = ["apple-catalog-parsing"]
|
|
100
|
+
|
|
101
|
+
[workspace.lints.clippy]
|
|
102
|
+
allow-attributes = "warn"
|
|
103
|
+
unnecessary-wraps = "warn"
|
|
104
|
+
unwrap-used = "warn"
|
|
105
|
+
|
|
106
|
+
[lints]
|
|
107
|
+
workspace = true
|
|
108
|
+
|
|
94
109
|
[target]
|
|
95
110
|
|
|
96
111
|
[target."cfg(target_os = \"macos\")"]
|
|
97
112
|
|
|
98
113
|
[target."cfg(target_os = \"macos\")".dependencies]
|
|
99
114
|
mac-process-info = "0.2.0"
|
|
115
|
+
apple-catalog-parsing = { path = "apple-catalog-parsing" }
|
|
100
116
|
|
|
101
117
|
[target."cfg(unix)"]
|
|
102
118
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sentry_cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.47.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
|
|
@@ -43,7 +43,7 @@ Fastlane tools.
|
|
|
43
43
|
|
|
44
44
|
## Installation
|
|
45
45
|
|
|
46
|
-
If you are on
|
|
46
|
+
If you are on macOS or Linux, you can use the automated downloader which will fetch the latest release version for you and install it:
|
|
47
47
|
|
|
48
48
|
curl -sL https://sentry.io/get-cli/ | bash
|
|
49
49
|
|
|
@@ -25,7 +25,7 @@ Fastlane tools.
|
|
|
25
25
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
28
|
-
If you are on
|
|
28
|
+
If you are on macOS or Linux, you can use the automated downloader which will fetch the latest release version for you and install it:
|
|
29
29
|
|
|
30
30
|
curl -sL https://sentry.io/get-cli/ | bash
|
|
31
31
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
use std::env;
|
|
2
|
+
use std::process::Command;
|
|
3
|
+
|
|
4
|
+
fn main() {
|
|
5
|
+
let target = env::var("TARGET").expect("TARGET is set for build scripts");
|
|
6
|
+
let mut target_bits = target.split('-');
|
|
7
|
+
|
|
8
|
+
// https://rust-lang.github.io/rfcs/0131-target-specification.html#detailed-design
|
|
9
|
+
let mut arch = target_bits.next().expect("TARGET triple has an arch");
|
|
10
|
+
let _vendor = target_bits.next();
|
|
11
|
+
let platform = target_bits.next().expect("TARGET triple has a platform");
|
|
12
|
+
|
|
13
|
+
if platform != "darwin" {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if arch == "aarch64" {
|
|
18
|
+
arch = "arm64"; // enforce Darwin naming conventions
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
println!("cargo:rerun-if-changed=native/swift/AssetCatalogParser");
|
|
22
|
+
|
|
23
|
+
let out_dir = env::var("OUT_DIR").expect("OUT_DIR is set for build scripts");
|
|
24
|
+
|
|
25
|
+
// Compile Swift code
|
|
26
|
+
let status = Command::new("swift")
|
|
27
|
+
.args([
|
|
28
|
+
"build",
|
|
29
|
+
"-c",
|
|
30
|
+
"release",
|
|
31
|
+
"--package-path",
|
|
32
|
+
"native/swift/AssetCatalogParser",
|
|
33
|
+
"--scratch-path",
|
|
34
|
+
&format!("{out_dir}/swift-scratch"),
|
|
35
|
+
"--triple",
|
|
36
|
+
&format!("{arch}-apple-macosx10.12"),
|
|
37
|
+
])
|
|
38
|
+
.status()
|
|
39
|
+
.expect("Failed to compile SPM");
|
|
40
|
+
|
|
41
|
+
assert!(status.success(), "swift build failed");
|
|
42
|
+
|
|
43
|
+
// Create a static library of the Swift and Objective-C code
|
|
44
|
+
let status = Command::new("ar")
|
|
45
|
+
.args([
|
|
46
|
+
"crus",
|
|
47
|
+
&format!("{out_dir}/libswiftbridge.a"),
|
|
48
|
+
&format!(
|
|
49
|
+
"{out_dir}/swift-scratch/release/AssetCatalogParser.build/AssetCatalogReader.swift.o"
|
|
50
|
+
),
|
|
51
|
+
&format!(
|
|
52
|
+
"{out_dir}/swift-scratch/release/ObjcSupport.build/safeValueForKey.m.o",
|
|
53
|
+
),
|
|
54
|
+
])
|
|
55
|
+
.status()
|
|
56
|
+
.expect("Failed to create static library");
|
|
57
|
+
|
|
58
|
+
assert!(status.success(), "ar failed");
|
|
59
|
+
|
|
60
|
+
// Add the new static library to search paths and link to it
|
|
61
|
+
println!("cargo:rustc-link-search=native={out_dir}");
|
|
62
|
+
println!("cargo:rustc-link-lib=static=swiftbridge");
|
|
63
|
+
|
|
64
|
+
// Link to CoreUI framework
|
|
65
|
+
println!("cargo:rustc-link-search=framework=/System/Library/PrivateFrameworks");
|
|
66
|
+
println!("cargo:rustc-link-lib=framework=CoreUI");
|
|
67
|
+
|
|
68
|
+
// Link to swift macOS support libraries for Swift runtime support on older macOS versions
|
|
69
|
+
let developer_dir = Command::new("xcode-select")
|
|
70
|
+
.args(["-p"])
|
|
71
|
+
.output()
|
|
72
|
+
.expect("Failed to get developer directory, please ensure Xcode is installed.");
|
|
73
|
+
let developer_dir_path = String::from_utf8(developer_dir.stdout)
|
|
74
|
+
.expect("Failed to convert developer directory to UTF-8")
|
|
75
|
+
.trim()
|
|
76
|
+
.to_string();
|
|
77
|
+
|
|
78
|
+
println!(
|
|
79
|
+
"cargo:rustc-link-search={developer_dir_path}/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// swift-tools-version: 5.10
|
|
2
|
+
|
|
3
|
+
import PackageDescription
|
|
4
|
+
|
|
5
|
+
let package = Package(
|
|
6
|
+
name: "AssetCatalogParser",
|
|
7
|
+
platforms: [
|
|
8
|
+
.macOS(.v11),
|
|
9
|
+
],
|
|
10
|
+
products: [
|
|
11
|
+
.library(
|
|
12
|
+
name: "AssetCatalogParser",
|
|
13
|
+
targets: ["AssetCatalogParser"]),
|
|
14
|
+
],
|
|
15
|
+
targets: [
|
|
16
|
+
.target(
|
|
17
|
+
name: "AssetCatalogParser",
|
|
18
|
+
dependencies: ["ObjcSupport"],
|
|
19
|
+
linkerSettings: [
|
|
20
|
+
.unsafeFlags([
|
|
21
|
+
"-F", "/System/Library/PrivateFrameworks",
|
|
22
|
+
"-framework", "CoreUI",
|
|
23
|
+
])
|
|
24
|
+
]),
|
|
25
|
+
.target(name: "ObjcSupport"),
|
|
26
|
+
.testTarget(
|
|
27
|
+
name: "AssetCatalogParserTests",
|
|
28
|
+
dependencies: ["AssetCatalogParser"],
|
|
29
|
+
resources: [
|
|
30
|
+
.copy("Resources")
|
|
31
|
+
])
|
|
32
|
+
]
|
|
33
|
+
)
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import CoreGraphics
|
|
2
|
+
import Foundation
|
|
3
|
+
import ImageIO
|
|
4
|
+
import UniformTypeIdentifiers
|
|
5
|
+
import ObjcSupport
|
|
6
|
+
|
|
7
|
+
@_cdecl("swift_inspect_asset_catalog")
|
|
8
|
+
// Insepects the asset catalog and writes the results to a JSON file
|
|
9
|
+
// in the xcarchive containing the asset catalog.
|
|
10
|
+
public func swift_inspect_asset_catalog(_ path: UnsafePointer<CChar>) {
|
|
11
|
+
let pathString = String(cString: path)
|
|
12
|
+
if #available(macOS 13.0, *) {
|
|
13
|
+
let supportedVersions = [13, 14, 15]
|
|
14
|
+
let version = ProcessInfo.processInfo.operatingSystemVersion
|
|
15
|
+
if supportedVersions.contains(version.majorVersion) {
|
|
16
|
+
AssetUtil.disect(file: URL(filePath: pathString))
|
|
17
|
+
} else {
|
|
18
|
+
print("Skipping asset catalog inspection on unsupported macOS version \(version)")
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
print("Skipping asset catalog inspection on macOS earlier than 13.0")
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
enum AssetType: Int, Encodable {
|
|
26
|
+
case image
|
|
27
|
+
case icon
|
|
28
|
+
case imageSet
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
struct AssetCatalogEntry: Encodable {
|
|
32
|
+
let imageId: String
|
|
33
|
+
let size: UInt
|
|
34
|
+
let name: String
|
|
35
|
+
let vector: Bool
|
|
36
|
+
let width: Int?
|
|
37
|
+
let height: Int?
|
|
38
|
+
let filename: String?
|
|
39
|
+
let type: AssetType?
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
enum Error: Swift.Error {
|
|
43
|
+
case pathError
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
typealias objectiveCMethodImp = @convention(c) (AnyObject, Selector, UnsafeRawPointer) -> Unmanaged<
|
|
47
|
+
AnyObject
|
|
48
|
+
>?
|
|
49
|
+
|
|
50
|
+
enum AssetUtil {
|
|
51
|
+
private static func createResultsPath(assetPath: URL) throws -> URL {
|
|
52
|
+
var archiveURL = assetPath
|
|
53
|
+
var tailComponents: [String] = []
|
|
54
|
+
while archiveURL.pathExtension != "xcarchive" && archiveURL.pathComponents.count > 1 {
|
|
55
|
+
tailComponents.insert(archiveURL.lastPathComponent, at: 0)
|
|
56
|
+
archiveURL.deleteLastPathComponent()
|
|
57
|
+
}
|
|
58
|
+
if archiveURL.pathExtension != "xcarchive" {
|
|
59
|
+
throw Error.pathError
|
|
60
|
+
}
|
|
61
|
+
let parsedRoot = archiveURL.appendingPathComponent("ParsedAssets",
|
|
62
|
+
isDirectory: true)
|
|
63
|
+
let destDir = tailComponents
|
|
64
|
+
.dropLast()
|
|
65
|
+
.reduce(parsedRoot) { partial, next in
|
|
66
|
+
partial.appendingPathComponent(next, isDirectory: true)
|
|
67
|
+
}
|
|
68
|
+
try! FileManager.default.createDirectory(at: destDir,
|
|
69
|
+
withIntermediateDirectories: true)
|
|
70
|
+
return destDir
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@discardableResult static func disect(file: URL) -> [AssetCatalogEntry] {
|
|
74
|
+
var assets: [AssetCatalogEntry] = []
|
|
75
|
+
var colorLength: UInt = 0
|
|
76
|
+
var colorCount = 0
|
|
77
|
+
|
|
78
|
+
let (structuredThemeStore, assetKeys) = initializeCatalog(from: file)
|
|
79
|
+
|
|
80
|
+
var images: [String: CGImage] = [:]
|
|
81
|
+
|
|
82
|
+
for key in assetKeys {
|
|
83
|
+
let keyList = unsafeBitCast(
|
|
84
|
+
key.perform(Selector(("keyList"))),
|
|
85
|
+
to: UnsafeMutableRawPointer.self
|
|
86
|
+
)
|
|
87
|
+
let rendition = createRendition(from: structuredThemeStore, keyList)
|
|
88
|
+
|
|
89
|
+
let data = rendition.value(forKey: "_srcData") as! Data
|
|
90
|
+
let length = UInt(data.count)
|
|
91
|
+
let className = rendition.perform(Selector(("className"))).takeUnretainedValue() as! String
|
|
92
|
+
let renditionTypeName =
|
|
93
|
+
rendition.perform(Selector(("name"))).takeUnretainedValue() as! String
|
|
94
|
+
|
|
95
|
+
var packedAssetSize: UInt = 0
|
|
96
|
+
if renditionTypeName.hasPrefix("ZZZZPacked") {
|
|
97
|
+
packedAssetSize += length
|
|
98
|
+
continue
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if handleReferenceKey(
|
|
102
|
+
rendition,
|
|
103
|
+
structuredThemeStore,
|
|
104
|
+
Selector(("renditionWithKey:")),
|
|
105
|
+
&packedAssetSize,
|
|
106
|
+
renditionTypeName,
|
|
107
|
+
length
|
|
108
|
+
) {
|
|
109
|
+
continue
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if className == "_CUIThemeColorRendition" {
|
|
113
|
+
colorCount += 1
|
|
114
|
+
colorLength += length
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let name = resolveRenditionName(
|
|
119
|
+
structuredThemeStore,
|
|
120
|
+
keyList,
|
|
121
|
+
renditionTypeName
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
let type = rendition.getUInt(forKey: "type") ?? 0
|
|
125
|
+
|
|
126
|
+
let isVector = type == 9
|
|
127
|
+
let (width, height, unslicedImage) = resolveImageDimensions(rendition, isVector)
|
|
128
|
+
let assetType = determineAssetType(key)
|
|
129
|
+
let imageId = UUID().uuidString
|
|
130
|
+
images[imageId] = unslicedImage
|
|
131
|
+
|
|
132
|
+
let asset = AssetCatalogEntry(
|
|
133
|
+
imageId: imageId,
|
|
134
|
+
size: length,
|
|
135
|
+
name: name,
|
|
136
|
+
vector: isVector,
|
|
137
|
+
width: width,
|
|
138
|
+
height: height,
|
|
139
|
+
filename: renditionTypeName,
|
|
140
|
+
type: assetType
|
|
141
|
+
)
|
|
142
|
+
assets.append(asset)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
assets.append(AssetCatalogEntry(
|
|
146
|
+
imageId: "",
|
|
147
|
+
size: colorLength,
|
|
148
|
+
name: "\(colorCount) Color\(colorCount > 1 ? "s" : "")",
|
|
149
|
+
vector: false,
|
|
150
|
+
width: nil,
|
|
151
|
+
height: nil,
|
|
152
|
+
filename: nil,
|
|
153
|
+
type: nil
|
|
154
|
+
))
|
|
155
|
+
|
|
156
|
+
let data = try! JSONEncoder().encode(assets)
|
|
157
|
+
let folder = try! createResultsPath(assetPath: file)
|
|
158
|
+
let url = folder
|
|
159
|
+
.appendingPathComponent("Assets")
|
|
160
|
+
.appendingPathExtension("json")
|
|
161
|
+
try! data.write(to: url, options: [])
|
|
162
|
+
for (id, cgImage) in images {
|
|
163
|
+
let fileURL = folder.appendingPathComponent(id)
|
|
164
|
+
.appendingPathExtension("png")
|
|
165
|
+
|
|
166
|
+
guard let dest = CGImageDestinationCreateWithURL(
|
|
167
|
+
fileURL as CFURL,
|
|
168
|
+
UTType.png.identifier as CFString,
|
|
169
|
+
1,
|
|
170
|
+
nil
|
|
171
|
+
)
|
|
172
|
+
else {
|
|
173
|
+
print("⚠️ Could not create destination for \(fileURL.path)")
|
|
174
|
+
continue
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
CGImageDestinationAddImage(dest, cgImage, nil)
|
|
178
|
+
CGImageDestinationFinalize(dest)
|
|
179
|
+
}
|
|
180
|
+
return assets
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private static func initializeCatalog(from file: URL) -> (
|
|
184
|
+
themeStore: NSObject, assetKeys: [NSObject]
|
|
185
|
+
) {
|
|
186
|
+
let catalogClass: NSObject.Type = NSClassFromString("CUICatalog")! as! NSObject.Type
|
|
187
|
+
var catalog: NSObject =
|
|
188
|
+
catalogClass.perform(Selector(("alloc"))).takeRetainedValue() as! NSObject
|
|
189
|
+
catalog =
|
|
190
|
+
catalog.perform(Selector(("initWithURL:error:")), with: file as NSURL, with: nil)
|
|
191
|
+
.takeUnretainedValue() as! NSObject
|
|
192
|
+
let structuredThemeStore =
|
|
193
|
+
catalog.perform(Selector(("_themeStore"))).takeUnretainedValue() as! NSObject
|
|
194
|
+
let assetStorage = structuredThemeStore.perform(Selector(("themeStore"))).takeUnretainedValue()
|
|
195
|
+
let assetKeys =
|
|
196
|
+
assetStorage.perform(Selector(("allAssetKeys"))).takeUnretainedValue() as! [NSObject]
|
|
197
|
+
return (structuredThemeStore, assetKeys)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private static func createRendition(from themeStore: NSObject, _ keyList: UnsafeMutableRawPointer)
|
|
201
|
+
-> NSObject
|
|
202
|
+
{
|
|
203
|
+
let renditionWithKeySelector = Selector(("renditionWithKey:"))
|
|
204
|
+
let renditionWithKeyMethod = themeStore.method(for: renditionWithKeySelector)!
|
|
205
|
+
let renditionWithKeyImp = unsafeBitCast(renditionWithKeyMethod, to: objectiveCMethodImp.self)
|
|
206
|
+
return renditionWithKeyImp(themeStore, renditionWithKeySelector, keyList)!.takeUnretainedValue()
|
|
207
|
+
as! NSObject
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private static func handleReferenceKey(
|
|
211
|
+
_ rendition: NSObject,
|
|
212
|
+
_ themeStore: NSObject,
|
|
213
|
+
_: Selector,
|
|
214
|
+
_ packedAssetSize: inout UInt,
|
|
215
|
+
_: String,
|
|
216
|
+
_ length: UInt
|
|
217
|
+
) -> Bool {
|
|
218
|
+
let referenceKey = safeValueForKey(rendition, "_referenceKey")
|
|
219
|
+
guard let referenceKey = referenceKey as? NSObject else { return false }
|
|
220
|
+
|
|
221
|
+
let referenceKeyList = unsafeBitCast(
|
|
222
|
+
referenceKey.perform(Selector(("keyList"))),
|
|
223
|
+
to: UnsafeMutableRawPointer.self
|
|
224
|
+
)
|
|
225
|
+
let referenceRendition = createRendition(from: themeStore, referenceKeyList)
|
|
226
|
+
|
|
227
|
+
if let result = referenceRendition.perform(Selector(("unslicedImage"))) {
|
|
228
|
+
let image = result.takeUnretainedValue() as! CGImage
|
|
229
|
+
if image.dataProvider?.data as? Data != nil {
|
|
230
|
+
packedAssetSize += length
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return true
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private static func determineAssetType(_ key: NSObject) -> AssetType {
|
|
237
|
+
let themeElement = key.getUInt(forKey: "themeElement") ?? 0
|
|
238
|
+
let themePart = key.getUInt(forKey: "themePart") ?? 0
|
|
239
|
+
|
|
240
|
+
if themeElement == 85, themePart == 220 {
|
|
241
|
+
return .icon
|
|
242
|
+
} else if themeElement == 9 {
|
|
243
|
+
return .imageSet
|
|
244
|
+
}
|
|
245
|
+
return .image
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private static func resolveRenditionName(
|
|
249
|
+
_ structuredThemeStore: NSObject,
|
|
250
|
+
_ keyList: UnsafeMutableRawPointer,
|
|
251
|
+
_ renditionTypeName: String
|
|
252
|
+
) -> String {
|
|
253
|
+
let renditionNameForKeyListSelector = Selector(("renditionNameForKeyList:"))
|
|
254
|
+
let renditionNameForKeyListMethod = structuredThemeStore.method(
|
|
255
|
+
for: renditionNameForKeyListSelector
|
|
256
|
+
)!
|
|
257
|
+
let renditionNameForKeyList = unsafeBitCast(
|
|
258
|
+
renditionNameForKeyListMethod,
|
|
259
|
+
to: objectiveCMethodImp.self
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
var renditionName: String?
|
|
263
|
+
if let result = renditionNameForKeyList(
|
|
264
|
+
structuredThemeStore,
|
|
265
|
+
renditionNameForKeyListSelector,
|
|
266
|
+
keyList
|
|
267
|
+
) {
|
|
268
|
+
renditionName = result.takeUnretainedValue() as? String
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let name = renditionTypeName == "CoreStructuredImage" ? renditionName : renditionTypeName
|
|
272
|
+
return name!
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private static func resolveImageDimensions(_ rendition: NSObject, _ isVector: Bool) -> (
|
|
276
|
+
width: Int?, height: Int?, image: CGImage?
|
|
277
|
+
) {
|
|
278
|
+
var unslicedImage: CGImage?
|
|
279
|
+
if let result = rendition.perform(Selector(("unslicedImage"))) {
|
|
280
|
+
unslicedImage = (result.takeUnretainedValue() as! CGImage)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
var width: Int?
|
|
284
|
+
var height: Int?
|
|
285
|
+
if !isVector {
|
|
286
|
+
width = unslicedImage?.width
|
|
287
|
+
height = unslicedImage?.height
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return (width, height, unslicedImage)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private extension NSObject {
|
|
295
|
+
func getUInt(forKey key: String) -> UInt? {
|
|
296
|
+
if let result = perform(Selector(key)) {
|
|
297
|
+
return UInt(bitPattern: result.toOpaque())
|
|
298
|
+
}
|
|
299
|
+
return nil
|
|
300
|
+
}
|
|
301
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import "safeValueForKey.h"
|
|
3
|
+
|
|
4
|
+
// Helper to call `valueForKey` without swift crashing
|
|
5
|
+
id safeValueForKey(id object, NSString *key) {
|
|
6
|
+
@try {
|
|
7
|
+
return [object valueForKey:key];
|
|
8
|
+
} @catch (NSException *exception) {
|
|
9
|
+
return nil;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
@testable import AssetCatalogParser
|
|
2
|
+
import Testing
|
|
3
|
+
import Foundation
|
|
4
|
+
|
|
5
|
+
struct AssetCatalogParserTests {
|
|
6
|
+
@Test func testParseAssets() throws {
|
|
7
|
+
let archivePath = try #require(Bundle.module.path(forResource: "test", ofType: "xcarchive"))
|
|
8
|
+
let url = URL(filePath: "\(archivePath)/Products/Applications/DemoApp.app/Assets.car")
|
|
9
|
+
let results = AssetUtil.disect(file: url)
|
|
10
|
+
#expect(results.count == 2)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>ApplicationProperties</key>
|
|
6
|
+
<dict>
|
|
7
|
+
<key>ApplicationPath</key>
|
|
8
|
+
<string>Applications/DemoApp.app</string>
|
|
9
|
+
<key>Architectures</key>
|
|
10
|
+
<array>
|
|
11
|
+
<string>arm64</string>
|
|
12
|
+
</array>
|
|
13
|
+
<key>CFBundleIdentifier</key>
|
|
14
|
+
<string>com.emerge.PreviewsDemoApp</string>
|
|
15
|
+
<key>CFBundleShortVersionString</key>
|
|
16
|
+
<string>1.0</string>
|
|
17
|
+
<key>CFBundleVersion</key>
|
|
18
|
+
<string>1</string>
|
|
19
|
+
<key>SigningIdentity</key>
|
|
20
|
+
<string>Apple Development: Noah Martin (5TV9RX846L)</string>
|
|
21
|
+
<key>Team</key>
|
|
22
|
+
<string>62J2XHNK9T</string>
|
|
23
|
+
</dict>
|
|
24
|
+
<key>ArchiveVersion</key>
|
|
25
|
+
<integer>2</integer>
|
|
26
|
+
<key>CreationDate</key>
|
|
27
|
+
<date>2024-03-02T16:16:02Z</date>
|
|
28
|
+
<key>Name</key>
|
|
29
|
+
<string>DemoApp</string>
|
|
30
|
+
<key>SchemeName</key>
|
|
31
|
+
<string>DemoApp</string>
|
|
32
|
+
</dict>
|
|
33
|
+
</plist>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
use std::ffi::CString;
|
|
2
|
+
use std::os::unix::ffi::OsStrExt;
|
|
3
|
+
use std::path::Path;
|
|
4
|
+
use thiserror::Error;
|
|
5
|
+
|
|
6
|
+
#[derive(Error, Debug)]
|
|
7
|
+
#[non_exhaustive]
|
|
8
|
+
pub enum Error {
|
|
9
|
+
#[error("Failed to convert path to C string: {0}")]
|
|
10
|
+
PathConversion(#[from] std::ffi::NulError),
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
extern "C" {
|
|
14
|
+
fn swift_inspect_asset_catalog(msg: *const std::os::raw::c_char);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/// This calls out to Swift code that uses Apple APIs to convert the contents
|
|
18
|
+
/// of an asset catalog into a format that can be parsed by the
|
|
19
|
+
/// size analysis backend. It enables main size analysis features such
|
|
20
|
+
/// as duplicate image detection, xray, and image optimization insights.
|
|
21
|
+
/// The path should be in an xcarchive file, results are written
|
|
22
|
+
/// to a JSON file in the xcarchive’s ParsedAssets directory.
|
|
23
|
+
pub fn inspect_asset_catalog<P>(path: P) -> Result<(), Error>
|
|
24
|
+
where
|
|
25
|
+
P: AsRef<Path>,
|
|
26
|
+
{
|
|
27
|
+
let c_string = CString::new(path.as_ref().as_os_str().as_bytes())?;
|
|
28
|
+
let string_ptr = c_string.as_ptr();
|
|
29
|
+
unsafe {
|
|
30
|
+
// The string pointed to is immutable, in Swift we cannot change it.
|
|
31
|
+
// We ensure this by using "UnsafePointer<CChar>" in Swift which is
|
|
32
|
+
// immutable (as opposed to "UnsafeMutablePointer<CChar>").
|
|
33
|
+
swift_inspect_asset_catalog(string_ptr);
|
|
34
|
+
}
|
|
35
|
+
Ok(())
|
|
36
|
+
}
|