Retry steps of granting Xcode automation permission on failure
Bug: https://github.com/flutter/flutter/issues/139693
Change-Id: I4b41fa2ebcb82c6b4756f20bab93020d6bfe8400
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/53040
Commit-Queue: Victoria Ashworth <vashworth@google.com>
Reviewed-by: Keyong Han <keyonghan@google.com>
diff --git a/recipe_modules/os_utils/__init__.py b/recipe_modules/os_utils/__init__.py
index 1df74ac..a164017 100644
--- a/recipe_modules/os_utils/__init__.py
+++ b/recipe_modules/os_utils/__init__.py
@@ -1,5 +1,6 @@
DEPS = [
'flutter/repo_util',
+ 'flutter/retry',
'recipe_engine/context',
'recipe_engine/file',
'recipe_engine/path',
@@ -8,4 +9,5 @@
'recipe_engine/raw_io',
'recipe_engine/step',
'recipe_engine/swarming',
+ "recipe_engine/time",
]
diff --git a/recipe_modules/os_utils/api.py b/recipe_modules/os_utils/api.py
index 87e5a9c..7e545b9 100644
--- a/recipe_modules/os_utils/api.py
+++ b/recipe_modules/os_utils/api.py
@@ -351,7 +351,8 @@
cmd = [resource_name, device_id]
self.m.step('Run app to dismiss dialogs', cmd)
with self.m.step.nest('Dismiss Xcode automation dialogs'):
- self._dismiss_xcode_automation_dialogs(device_id)
+ with self.m.context(infra_steps=True):
+ self._dismiss_xcode_automation_dialogs(device_id)
def _dismiss_xcode_automation_dialogs(self, device_id):
"""Dismiss Xcode automation permission dialog and update permission db.
@@ -374,7 +375,6 @@
'devices',
'-v',
],
- infra_step=True,
raise_on_failure=False,
ok_ret='any',
)
@@ -391,7 +391,6 @@
'-v',
],
stdout=self.m.raw_io.output_text(),
- infra_step=True,
raise_on_failure=False,
ok_ret='any',
).stdout.rstrip()
@@ -410,17 +409,10 @@
tcc_directory_path, db_path, backup_db_path = self._get_tcc_path()
# Ensure db exists
- self.m.step(
- 'List TCC directory',
- ['ls', tcc_directory_path],
- infra_step=True,
- )
-
files = self.m.step(
'Find TCC directory',
['ls', tcc_directory_path],
- stdout=self.m.raw_io.output_text(),
- infra_step=True,
+ stdout=self.m.raw_io.output_text(add_output_log=True),
).stdout.rstrip()
if XCODE_AUTOMATION_DB not in files:
@@ -430,7 +422,7 @@
)
# Print contents of db for potential debugging purposes.
- self._query_automation_db_step(db_path)
+ self._query_automation_db_step_with_retry(db_path)
# Create backup db if there isn't one.
# If there is already a backup, it's most likely that a previous run did
@@ -439,13 +431,55 @@
self.m.step(
'Create backup db',
['cp', db_path, backup_db_path],
- infra_step=True,
)
+ self.m.retry.basic_wrap(
+ lambda timeout: self._trigger_automation_permission(
+ db_path,
+ timeout=timeout,
+ ),
+ step_name='Wait to add entry in TCC db',
+ sleep=2.0,
+ backoff_factor=2,
+ max_attempts=3,
+ timeout=2,
+ )
+
+ # Update TCC.db. If fails, try up to 3 times. It may fail if the db is locked.
+ self.m.retry.basic_wrap(
+ lambda timeout: self._update_automation_permission_db(
+ db_path,
+ timeout=timeout,
+ ),
+ step_name='Wait to update TCC db',
+ sleep=2.0,
+ backoff_factor=2,
+ max_attempts=3
+ )
+
+ # Print contents of db for potential debugging purposes.
+ self._query_automation_db_step_with_retry(db_path)
+
+ # Xcode was opened by Applescript, so kill it.
+ self.m.step(
+ 'Kill Xcode',
+ ['killall', '-9', 'Xcode'],
+ ok_ret='any',
+ )
+
+ def _trigger_automation_permission(self, db_path, timeout=2):
+ """Trigger Xcode automation dialog to appear and then kill the dialog.
+ Killing the dialog will add an entry for the permission to the TCC.db.
+ Raises an error if dialog fails to add entry to db.
+
+ Args:
+ db_path(string): A string of the path to the sqlite database.
+ """
+
# Run an arbitrary AppleScript Xcode command to trigger permissions dialog.
# The AppleScript counts how many Xcode windows are open.
# The script will hang if permission has not been given, so timeout after
- # a few seconds.
+ # a few seconds. For each attempt, use a longer timeout.
self.m.step(
'Trigger dialog',
[
@@ -459,10 +493,9 @@
'-e',
'end tell',
],
- infra_step=True,
raise_on_failure=False,
ok_ret='any',
- timeout=2,
+ timeout=timeout,
)
# Kill the dialog. After killing the dialog, an entry for the app requesting
@@ -470,33 +503,11 @@
self.m.step(
'Dismiss dialog',
['killall', '-9', 'UserNotificationCenter'],
- infra_step=True,
ok_ret='any',
)
- # Print contents of db for potential debugging purposes.
- self._query_automation_db_step(db_path)
-
- # Update the db to make it think permission was given.
- self.m.step(
- 'Update db',
- [
- 'sqlite3', db_path,
- "UPDATE access SET auth_value = 2, auth_reason = 3, flags = NULL WHERE service = 'kTCCServiceAppleEvents' AND indirect_object_identifier = 'com.apple.dt.Xcode'"
- ],
- infra_step=True,
- )
-
- # Print contents of db for potential debugging purposes.
- self._query_automation_db_step(db_path)
-
- # Xcode was opened by Applescript, so kill it.
- self.m.step(
- 'Kill Xcode',
- ['killall', '-9', 'Xcode'],
- infra_step=True,
- ok_ret='any',
- )
+ if 'Xcode' not in self._query_automation_db_step_with_retry(db_path):
+ raise self.m.step.InfraFailure('Xcode entry not found in TCC.db')
def _get_tcc_path(self):
"""Constructs paths to the TCC directory, TCC db, and TCC backup db.
@@ -516,21 +527,59 @@
)
return tcc_directory_path, db_path, backup_db_path
- def _query_automation_db_step(self, db_path):
+ # pylint: disable=unused-argument
+ def _update_automation_permission_db(self, db_path, timeout=None):
+ self.m.step(
+ 'Update db',
+ [
+ 'sqlite3', db_path,
+ "UPDATE access SET auth_value = 2, auth_reason = 3, flags = NULL WHERE service = 'kTCCServiceAppleEvents' AND indirect_object_identifier = 'com.apple.dt.Xcode'"
+ ],
+ )
+
+ def _query_automation_db_step_with_retry(self, db_path):
+ """Queries the TCC database with 3 retries. Sometimes if the database is
+ locked, query will fail. So wait and try again.
+
+ Args:
+ db_path(string): A string of the path to the sqlite database.
+
+ Returns:
+ A string of the query's output.
+ """
+
+ return self.m.retry.basic_wrap(
+ lambda timeout: self._query_automation_db_step(
+ db_path,
+ timeout=timeout,
+ ),
+ step_name='Wait to query TCC db',
+ sleep=2.0,
+ backoff_factor=1,
+ max_attempts=3
+ )
+
+ # pylint: disable=unused-argument
+ def _query_automation_db_step(self, db_path, timeout=None):
"""Queries the TCC database.
Args:
db_path(string): A string of the path to the sqlite database.
+
+ Returns:
+ A string of the query's output.
"""
- self.m.step(
+ query_results = self.m.step(
'Query TCC db',
[
'sqlite3', db_path,
'SELECT service, client, client_type, auth_value, auth_reason, indirect_object_identifier_type, indirect_object_identifier, flags, last_modified FROM access WHERE service = "kTCCServiceAppleEvents"'
],
- infra_step=True,
+ stdout=self.m.raw_io.output_text(add_output_log=True),
)
+ return query_results.stdout.rstrip()
+
def reset_automation_dialogs(self):
"""Reset Xcode Automation permissions."""
if str(self.m.swarming.bot_id
@@ -560,7 +609,7 @@
)
# Print contents of db for potential debugging purposes.
- self._query_automation_db_step(db_path)
+ self._query_automation_db_step_with_retry(db_path)
def _checkout_cocoon(self):
"""Checkout cocoon at HEAD to the cache and return the path."""
diff --git a/recipe_modules/os_utils/examples/full.expected/clean_derived_data.json b/recipe_modules/os_utils/examples/full.expected/clean_derived_data.json
index 9112833..3592f1e 100644
--- a/recipe_modules/os_utils/examples/full.expected/clean_derived_data.json
+++ b/recipe_modules/os_utils/examples/full.expected/clean_derived_data.json
@@ -521,20 +521,11 @@
"Users/fakeuser/Library/Application Support/com.apple.TCC"
],
"infra_step": true,
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.List TCC directory",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
- ]
- },
- {
- "cmd": [
- "ls",
- "Users/fakeuser/Library/Application Support/com.apple.TCC"
- ],
- "infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@TCC.db@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -546,7 +537,8 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -601,7 +593,9 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@service|client|client_type|auth_value|auth_reason|auth_version|com.apple.dt.Xcode|flags|last_modified@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -625,7 +619,8 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (3)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
diff --git a/recipe_modules/os_utils/examples/full.expected/dimiss_dialog_xcode_automation_fails_find_db.json b/recipe_modules/os_utils/examples/full.expected/dimiss_dialog_xcode_automation_fails_find_db.json
index 17de95f..d1a8025 100644
--- a/recipe_modules/os_utils/examples/full.expected/dimiss_dialog_xcode_automation_fails_find_db.json
+++ b/recipe_modules/os_utils/examples/full.expected/dimiss_dialog_xcode_automation_fails_find_db.json
@@ -525,20 +525,10 @@
"Users/fakeuser/Library/Application Support/com.apple.TCC"
],
"infra_step": true,
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.List TCC directory",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
- ]
- },
- {
- "cmd": [
- "ls",
- "Users/fakeuser/Library/Application Support/com.apple.TCC"
- ],
- "infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
diff --git a/recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_fails_find_db.json b/recipe_modules/os_utils/examples/full.expected/dimiss_dialog_xcode_automation_fails_update_db.json
similarity index 87%
copy from recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_fails_find_db.json
copy to recipe_modules/os_utils/examples/full.expected/dimiss_dialog_xcode_automation_fails_update_db.json
index 9308ce2..e6975c1 100644
--- a/recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_fails_find_db.json
+++ b/recipe_modules/os_utils/examples/full.expected/dimiss_dialog_xcode_automation_fails_update_db.json
@@ -312,7 +312,10 @@
},
{
"cmd": [],
- "name": "Dismiss dialogs"
+ "name": "Dismiss dialogs",
+ "~followup_annotations": [
+ "@@@STEP_EXCEPTION@@@"
+ ]
},
{
"cmd": [],
@@ -475,7 +478,8 @@
"cmd": [],
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@1@@@"
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_EXCEPTION@@@"
]
},
{
@@ -521,20 +525,11 @@
"Users/fakeuser/Library/Application Support/com.apple.TCC"
],
"infra_step": true,
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.List TCC directory",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
- ]
- },
- {
- "cmd": [
- "ls",
- "Users/fakeuser/Library/Application Support/com.apple.TCC"
- ],
- "infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@TCC.db@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -546,7 +541,8 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -601,17 +597,37 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)",
"~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "osascript",
+ "-e",
+ "tell app \"Xcode\"",
+ "-e",
+ "launch",
+ "-e",
+ "count window",
+ "-e",
+ "end tell"
+ ],
+ "infra_step": true,
+ "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Trigger dialog (2)",
+ "timeout": 4,
+ "~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [
- "sqlite3",
- "Users/fakeuser/Library/Application Support/com.apple.TCC/TCC.db",
- "UPDATE access SET auth_value = 2, auth_reason = 3, flags = NULL WHERE service = 'kTCCServiceAppleEvents' AND indirect_object_identifier = 'com.apple.dt.Xcode'"
+ "killall",
+ "-9",
+ "UserNotificationCenter"
],
"infra_step": true,
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Update db",
+ "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Dismiss dialog (2)",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
@@ -625,6 +641,26 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (3)",
"~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "osascript",
+ "-e",
+ "tell app \"Xcode\"",
+ "-e",
+ "launch",
+ "-e",
+ "count window",
+ "-e",
+ "end tell"
+ ],
+ "infra_step": true,
+ "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Trigger dialog (3)",
+ "timeout": 8,
+ "~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
@@ -632,82 +668,31 @@
"cmd": [
"killall",
"-9",
- "Xcode"
+ "UserNotificationCenter"
],
"infra_step": true,
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Kill Xcode",
+ "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Dismiss dialog (3)",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
- "cmd": [],
- "name": "Reset Xcode automation dialogs"
- },
- {
- "cmd": [
- "ls",
- "Users/fakeuser/Library/Application Support/com.apple.TCC"
- ],
- "infra_step": true,
- "name": "Reset Xcode automation dialogs.Find TCC directory",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@1@@@"
- ]
- },
- {
- "cmd": [
- "cp",
- "Users/fakeuser/Library/Application Support/com.apple.TCC/TCC.db.backup",
- "Users/fakeuser/Library/Application Support/com.apple.TCC/TCC.db"
- ],
- "name": "Reset Xcode automation dialogs.Restore from backup db",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@1@@@"
- ]
- },
- {
- "cmd": [
- "rm",
- "Users/fakeuser/Library/Application Support/com.apple.TCC/TCC.db.backup"
- ],
- "name": "Reset Xcode automation dialogs.Remove backup",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@1@@@"
- ]
- },
- {
"cmd": [
"sqlite3",
"Users/fakeuser/Library/Application Support/com.apple.TCC/TCC.db",
"SELECT service, client, client_type, auth_value, auth_reason, indirect_object_identifier_type, indirect_object_identifier, flags, last_modified FROM access WHERE service = \"kTCCServiceAppleEvents\""
],
"infra_step": true,
- "name": "Reset Xcode automation dialogs.Query TCC db",
+ "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (4)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@1@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
- "cmd": [
- "ln",
- "-s",
- "/a/file",
- "/a/b/c/simlink"
- ],
- "infra_step": true,
- "name": "Link /a/b/c/simlink to /a/file"
- },
- {
- "cmd": [
- "killall",
- "-9",
- "com.apple.CoreSimulator.CoreSimulatorDevice"
- ],
- "infra_step": true,
- "name": "kill dart"
- },
- {
+ "failure": {
+ "humanReason": "Xcode entry not found in TCC.db"
+ },
"name": "$result"
}
]
\ No newline at end of file
diff --git a/recipe_modules/os_utils/examples/full.expected/ios_debug_symbol_doctor_fails_then_succeeds.json b/recipe_modules/os_utils/examples/full.expected/ios_debug_symbol_doctor_fails_then_succeeds.json
index fe0a927..72c0fb3 100644
--- a/recipe_modules/os_utils/examples/full.expected/ios_debug_symbol_doctor_fails_then_succeeds.json
+++ b/recipe_modules/os_utils/examples/full.expected/ios_debug_symbol_doctor_fails_then_succeeds.json
@@ -555,20 +555,11 @@
"Users/fakeuser/Library/Application Support/com.apple.TCC"
],
"infra_step": true,
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.List TCC directory",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
- ]
- },
- {
- "cmd": [
- "ls",
- "Users/fakeuser/Library/Application Support/com.apple.TCC"
- ],
- "infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@TCC.db@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -580,7 +571,8 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -635,7 +627,9 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@service|client|client_type|auth_value|auth_reason|auth_version|com.apple.dt.Xcode|flags|last_modified@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -659,7 +653,8 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (3)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
diff --git a/recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_fails_find_db.json b/recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_finds_db.json
similarity index 95%
rename from recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_fails_find_db.json
rename to recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_finds_db.json
index 9308ce2..6535857 100644
--- a/recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_fails_find_db.json
+++ b/recipe_modules/os_utils/examples/full.expected/reset_dialog_xcode_automation_finds_db.json
@@ -521,20 +521,11 @@
"Users/fakeuser/Library/Application Support/com.apple.TCC"
],
"infra_step": true,
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.List TCC directory",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
- ]
- },
- {
- "cmd": [
- "ls",
- "Users/fakeuser/Library/Application Support/com.apple.TCC"
- ],
- "infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@TCC.db@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -546,7 +537,8 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -601,7 +593,9 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@service|client|client_type|auth_value|auth_reason|auth_version|com.apple.dt.Xcode|flags|last_modified@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -625,7 +619,8 @@
"infra_step": true,
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (3)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -682,10 +677,10 @@
"Users/fakeuser/Library/Application Support/com.apple.TCC/TCC.db",
"SELECT service, client, client_type, auth_value, auth_reason, indirect_object_identifier_type, indirect_object_identifier, flags, last_modified FROM access WHERE service = \"kTCCServiceAppleEvents\""
],
- "infra_step": true,
"name": "Reset Xcode automation dialogs.Query TCC db",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@1@@@"
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
diff --git a/recipe_modules/os_utils/examples/full.py b/recipe_modules/os_utils/examples/full.py
index 12d8399..29f37e5 100644
--- a/recipe_modules/os_utils/examples/full.py
+++ b/recipe_modules/os_utils/examples/full.py
@@ -45,6 +45,10 @@
'Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory',
stdout=api.raw_io.output_text('TCC.db'),
)
+ xcode_dismiss_dialog_query_db_step = api.step_data(
+ 'Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)',
+ stdout=api.raw_io.output_text('service|client|client_type|auth_value|auth_reason|auth_version|com.apple.dt.Xcode|flags|last_modified'),
+ )
yield api.test(
'basic',
api.platform('win', 64),
@@ -57,6 +61,7 @@
'ios_debug_symbol_doctor_fails_then_succeeds',
api.step_data('ios_debug_symbol_doctor.diagnose', retcode=1),
xcode_dismiss_dialog_find_db_step,
+ xcode_dismiss_dialog_query_db_step,
api.platform('mac', 64),
api.properties.environ(
properties.EnvProperties(SWARMING_BOT_ID='flutter-devicelab-mac-1')
@@ -86,6 +91,7 @@
yield api.test(
'clean_derived_data', api.platform('mac', 64),
xcode_dismiss_dialog_find_db_step,
+ xcode_dismiss_dialog_query_db_step,
api.properties.environ(
properties.EnvProperties(SWARMING_BOT_ID='flutter-devicelab-mac-1')
)
@@ -103,8 +109,19 @@
status='INFRA_FAILURE'
)
yield api.test(
- 'reset_dialog_xcode_automation_fails_find_db',
+ 'dimiss_dialog_xcode_automation_fails_update_db',
xcode_dismiss_dialog_find_db_step,
+ # xcode_dismiss_dialog_query_db_step,
+ api.platform('mac', 64),
+ api.properties.environ(
+ properties.EnvProperties(SWARMING_BOT_ID='flutter-devicelab-mac-1')
+ ),
+ status='INFRA_FAILURE'
+ )
+ yield api.test(
+ 'reset_dialog_xcode_automation_finds_db',
+ xcode_dismiss_dialog_find_db_step,
+ xcode_dismiss_dialog_query_db_step,
api.step_data(
'Reset Xcode automation dialogs.Find TCC directory',
stdout=api.raw_io.output_text('TCC.db.backup'),
diff --git a/recipe_modules/osx_sdk/api.py b/recipe_modules/osx_sdk/api.py
index 20c8658..0ce2a63 100644
--- a/recipe_modules/osx_sdk/api.py
+++ b/recipe_modules/osx_sdk/api.py
@@ -650,7 +650,8 @@
runtime_dmg_cache_dir
)
- def _is_runtimes_unmounted(self):
+ # pylint: disable=unused-argument
+ def _is_runtimes_unmounted(self, timeout=None):
'''Check if more than one runtime is currently mounted. If more than one
is mounted, raise a `StepFailure`.
'''
diff --git a/recipe_modules/repo_util/api.py b/recipe_modules/repo_util/api.py
index ca3b8bb..74f9809 100644
--- a/recipe_modules/repo_util/api.py
+++ b/recipe_modules/repo_util/api.py
@@ -128,7 +128,8 @@
self.m.file.ensure_directory('Ensure checkout cache', checkout_path)
# Inner function to execute code a second time in case of failure.
- def _InnerCheckout():
+ # pylint: disable=unused-argument
+ def _InnerCheckout(timeout=None):
with self.m.step.nest('Checkout source code'):
if clobber:
_ClobberCache()
@@ -224,7 +225,8 @@
self.m.file.ensure_directory('Ensure checkout cache', checkout_path)
# Inner function to execute code a second time in case of failure.
- def _InnerCheckout():
+ # pylint: disable=unused-argument
+ def _InnerCheckout(timeout=None):
with self.m.step.nest('Checkout source code'):
if clobber:
_ClobberCache()
diff --git a/recipe_modules/repo_util/examples/full.expected/monorepo_wrong_host.json b/recipe_modules/repo_util/examples/full.expected/monorepo_wrong_host.json
index 576304a..c76cd98 100644
--- a/recipe_modules/repo_util/examples/full.expected/monorepo_wrong_host.json
+++ b/recipe_modules/repo_util/examples/full.expected/monorepo_wrong_host.json
@@ -1144,7 +1144,7 @@
"Traceback (most recent call last):",
" File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/examples/full.py\", line 49, in RunSteps",
" api.repo_util.monorepo_checkout(checkout_path, {}, {})",
- " File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 210, in monorepo_checkout",
+ " File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 211, in monorepo_checkout",
" raise ValueError(",
"ValueError('Input reference is not on dart.googlesource.com/monorepo')"
]
diff --git a/recipe_modules/repo_util/examples/unsupported.expected/unsupported.json b/recipe_modules/repo_util/examples/unsupported.expected/unsupported.json
index 617ba98..e944c5f 100644
--- a/recipe_modules/repo_util/examples/unsupported.expected/unsupported.json
+++ b/recipe_modules/repo_util/examples/unsupported.expected/unsupported.json
@@ -9,7 +9,7 @@
"Traceback (most recent call last):",
" File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/examples/unsupported.py\", line 13, in RunSteps",
" api.repo_util.checkout('unsupported_repo', repo_dir)",
- " File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 287, in checkout",
+ " File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 289, in checkout",
" raise ValueError('Unsupported repo: %s' % name)",
"ValueError('Unsupported repo: unsupported_repo')"
]
diff --git a/recipe_modules/retry/api.py b/recipe_modules/retry/api.py
index fe6b78f..fb4c7c8 100644
--- a/recipe_modules/retry/api.py
+++ b/recipe_modules/retry/api.py
@@ -96,29 +96,33 @@
sleep *= backoff_factor
def basic_wrap(
- self, func, max_attempts=3, sleep=5.0, backoff_factor=1.5, **kwargs
+ self, func, max_attempts=3, sleep=5.0, backoff_factor=1.5, timeout=0, **kwargs
):
"""Retry basic wrapped function without step support.
Args:
func (callable): A function that performs the action that should be
- retried on failure. If it raises a `StepFailure`, it will be retried.
- Any other exception will end the retry loop and bubble up.
+ retried on failure. If it raises a `StepFailure` or `InfraFailure`,
+ it will be retried. Any other exception will end the retry loop and
+ bubble up.
max_attempts (int): How many times to try before giving up.
sleep (int or float): The initial time to sleep between attempts.
backoff_factor (int or float): The factor by which the sleep time
will be multiplied after each attempt.
+ timeout (int or float): A value passed to the `func` argument. Is
+ multiplied by the `backoff_factor` after each attempt.
Returns:
The result of executing func.
"""
for attempt in range(max_attempts):
try:
- result = func()
+ result = func(timeout=timeout)
return result
- except self.m.step.StepFailure:
+ except (self.m.step.StepFailure, self.m.step.InfraFailure):
if attempt == max_attempts - 1:
raise
self.m.time.sleep(sleep)
sleep *= backoff_factor
+ timeout *= backoff_factor
def run_flutter_doctor(self):
self.step(
diff --git a/recipe_modules/retry/examples/full.py b/recipe_modules/retry/examples/full.py
index 3b1929d..bd47615 100644
--- a/recipe_modules/retry/examples/full.py
+++ b/recipe_modules/retry/examples/full.py
@@ -38,7 +38,8 @@
def func1():
api.step('test: mytest_func', ['ls', '-a'])
- def func2():
+ # pylint: disable=unused-argument
+ def func2(timeout=None):
api.step('test: mytest_func_basic', ['ls', '-a'])
api.retry.wrap(
diff --git a/recipe_modules/shard_util_v2/api.py b/recipe_modules/shard_util_v2/api.py
index 451d623..ac7c0e4 100644
--- a/recipe_modules/shard_util_v2/api.py
+++ b/recipe_modules/shard_util_v2/api.py
@@ -517,7 +517,8 @@
cas_engine = cas_dir.join(target)
self.m.file.copytree('Copy host_debug_unopt', build_dir, cas_engine)
- def _upload():
+ # pylint: disable=unused-argument
+ def _upload(timeout=None):
return self.m.cas_util.upload(
cas_dir, step_name='Archive full build for %s' % target
)
diff --git a/recipes/devicelab/devicelab_drone.expected/xcode-devicelab-timeout.json b/recipes/devicelab/devicelab_drone.expected/xcode-devicelab-timeout.json
index 990dceb..76990f2 100644
--- a/recipes/devicelab/devicelab_drone.expected/xcode-devicelab-timeout.json
+++ b/recipes/devicelab/devicelab_drone.expected/xcode-devicelab-timeout.json
@@ -1890,54 +1890,11 @@
"hostname": "rdbhost"
}
},
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.List TCC directory",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
- ]
- },
- {
- "cmd": [
- "ls",
- "Users/fakeuser/Library/Application Support/com.apple.TCC"
- ],
- "cwd": "[CLEANUP]/tmp_tmp_1/flutter sdk/dev/devicelab",
- "env": {
- "ARTIFACT_HUB_REPOSITORY": "artifactregistry://us-maven.pkg.dev/artifact-foundry-prod/maven-3p",
- "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
- "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
- "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
- "GIT_BRANCH": "master",
- "LUCI_BRANCH": "",
- "LUCI_CI": "True",
- "LUCI_PR": "",
- "OS": "darwin",
- "PUB_CACHE": "[START_DIR]/.pub-cache",
- "REVISION": "12345abcde12345abcde12345abcde12345abcde",
- "SDK_CHECKOUT_PATH": "[CLEANUP]/tmp_tmp_1/flutter sdk",
- "USE_EMULATOR": "False"
- },
- "env_prefixes": {
- "PATH": [
- "[CLEANUP]/tmp_tmp_1/flutter sdk/bin",
- "[CLEANUP]/tmp_tmp_1/flutter sdk/bin/cache/dart-sdk/bin"
- ]
- },
- "infra_step": true,
- "luci_context": {
- "realm": {
- "name": "project:ci"
- },
- "resultdb": {
- "current_invocation": {
- "name": "invocations/build:8945511751514863184",
- "update_token": "token"
- },
- "hostname": "rdbhost"
- }
- },
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@TCC.db@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -1983,7 +1940,8 @@
},
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -2174,7 +2132,9 @@
},
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@service|client|client_type|auth_value|auth_reason|auth_version|com.apple.dt.Xcode|flags|last_modified@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -2266,7 +2226,8 @@
},
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (3)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
diff --git a/recipes/devicelab/devicelab_drone.expected/xcode-devicelab.json b/recipes/devicelab/devicelab_drone.expected/xcode-devicelab.json
index 996c5ae..f9db4dc 100644
--- a/recipes/devicelab/devicelab_drone.expected/xcode-devicelab.json
+++ b/recipes/devicelab/devicelab_drone.expected/xcode-devicelab.json
@@ -1890,54 +1890,11 @@
"hostname": "rdbhost"
}
},
- "name": "Dismiss dialogs.Dismiss Xcode automation dialogs.List TCC directory",
- "~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
- ]
- },
- {
- "cmd": [
- "ls",
- "Users/fakeuser/Library/Application Support/com.apple.TCC"
- ],
- "cwd": "[CLEANUP]/tmp_tmp_1/flutter sdk/dev/devicelab",
- "env": {
- "ARTIFACT_HUB_REPOSITORY": "artifactregistry://us-maven.pkg.dev/artifact-foundry-prod/maven-3p",
- "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
- "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
- "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
- "GIT_BRANCH": "master",
- "LUCI_BRANCH": "",
- "LUCI_CI": "True",
- "LUCI_PR": "",
- "OS": "darwin",
- "PUB_CACHE": "[START_DIR]/.pub-cache",
- "REVISION": "12345abcde12345abcde12345abcde12345abcde",
- "SDK_CHECKOUT_PATH": "[CLEANUP]/tmp_tmp_1/flutter sdk",
- "USE_EMULATOR": "False"
- },
- "env_prefixes": {
- "PATH": [
- "[CLEANUP]/tmp_tmp_1/flutter sdk/bin",
- "[CLEANUP]/tmp_tmp_1/flutter sdk/bin/cache/dart-sdk/bin"
- ]
- },
- "infra_step": true,
- "luci_context": {
- "realm": {
- "name": "project:ci"
- },
- "resultdb": {
- "current_invocation": {
- "name": "invocations/build:8945511751514863184",
- "update_token": "token"
- },
- "hostname": "rdbhost"
- }
- },
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@TCC.db@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -1983,7 +1940,8 @@
},
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -2174,7 +2132,9 @@
},
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@raw_io.output_text@service|client|client_type|auth_value|auth_reason|auth_version|com.apple.dt.Xcode|flags|last_modified@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
@@ -2266,7 +2226,8 @@
},
"name": "Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (3)",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@2@@@"
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_END@raw_io.output_text@@@"
]
},
{
diff --git a/recipes/devicelab/devicelab_drone.py b/recipes/devicelab/devicelab_drone.py
index d459325..44c2dfd 100644
--- a/recipes/devicelab/devicelab_drone.py
+++ b/recipes/devicelab/devicelab_drone.py
@@ -420,6 +420,10 @@
'Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory',
stdout=api.raw_io.output_text('TCC.db'),
),
+ api.step_data(
+ 'Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)',
+ stdout=api.raw_io.output_text('service|client|client_type|auth_value|auth_reason|auth_version|com.apple.dt.Xcode|flags|last_modified'),
+ ),
)
yield api.test(
"xcode-devicelab-timeout",
@@ -447,6 +451,10 @@
'Dismiss dialogs.Dismiss Xcode automation dialogs.Find TCC directory',
stdout=api.raw_io.output_text('TCC.db'),
),
+ api.step_data(
+ 'Dismiss dialogs.Dismiss Xcode automation dialogs.Query TCC db (2)',
+ stdout=api.raw_io.output_text('service|client|client_type|auth_value|auth_reason|auth_version|com.apple.dt.Xcode|flags|last_modified'),
+ ),
api.swarming.properties(bot_id='flutter-devicelab-mac-1'),
status='FAILURE',
)