@@ -27,7 +27,8 @@ def generate_app_intents_metadata_bundle(
2727 label ,
2828 source_files ,
2929 target_triples ,
30- xcode_version_config ):
30+ xcode_version_config ,
31+ json_tool ):
3132 """Process and generate AppIntents metadata bundle (Metadata.appintents).
3233
3334 Args:
@@ -42,6 +43,9 @@ def generate_app_intents_metadata_bundle(
4243 source_files: List of Swift source files implementing the AppIntents protocol.
4344 target_triples: List of Apple target triples from `CcToolchainInfo` providers.
4445 xcode_version_config: The `apple_common.XcodeVersionConfig` provider from the current ctx.
46+ json_tool: A `files_to_run` wrapping Python's `json.tool` module
47+ (https://docs.python.org/3.5/library/json.html#module-json.tool) for deterministic
48+ JSON handling.
4549 Returns:
4650 File referencing the Metadata.appintents bundle.
4751 """
@@ -102,16 +106,46 @@ an issue with the Apple BUILD rules with repro steps.
102106 ))
103107 args .add ("--xcode-version" , xcode_version_split [3 ])
104108
109+ json_tool_path = json_tool .executable .path
110+
105111 apple_support .run_shell (
106112 actions = actions ,
107113 apple_fragment = apple_fragment ,
108114 arguments = [args ],
109115 command = '''\
110116 set -euo pipefail
111117
118+ # sorts JSON file keys for deterministic output
119+ sort_json_file() {{
120+ local original_file="$1"
121+ local temp_file="${{original_file}}.sorted"
122+
123+ # Sort the JSON file keys
124+ "{json_tool_path}" --compact --sort-keys "$original_file" > "$temp_file"
125+ # Replace original with sorted version
126+ mv "$temp_file" "$original_file"
127+ }}
128+
112129exit_status=0
113130output=$($@ --sdk-root "$SDKROOT" --toolchain-dir "$DEVELOPER_DIR/Toolchains/XcodeDefault.xctoolchain" 2>&1) || exit_status=$?
114131
132+ # The Metadata.appintents/extract.actionsdata and version.json outputs are json
133+ # files with non-deterministic keys order.
134+ # Here we sort their keys to ensure that the output is deterministic.
135+ # This should be removed once the issue is fixed (FB19585633).
136+ actionsdata_file="{output_dir}/extract.actionsdata"
137+ version_file="{output_dir}/version.json"
138+
139+ # Sort both JSON files to ensure deterministic output
140+ sort_json_file "$version_file"
141+ sort_json_file "$actionsdata_file"
142+
143+ # Set write permission to allow rewriting files
144+ chmod +w "$version_file" "$actionsdata_file"
145+
146+ # Restore read-only permission
147+ chmod -w "$version_file" "$actionsdata_file"
148+
115149if [[ "$exit_status" -ne 0 ]]; then
116150 echo "$output" >&2
117151 exit $exit_status
@@ -122,8 +156,12 @@ elif [[ "$output" == *"skipping writing output"* ]]; then
122156 echo "$output" >&2
123157 exit 1
124158fi
125- ''' ,
159+ ''' .format (
160+ output_dir = output .path ,
161+ json_tool_path = json_tool_path ,
162+ ),
126163 inputs = depset ([bundle_binary ], transitive = transitive_inputs ),
164+ tools = [json_tool ],
127165 outputs = [output ],
128166 mnemonic = "AppIntentsMetadataProcessor" ,
129167 xcode_config = xcode_version_config ,
0 commit comments