Fix clobber cache retry for engine

This is a reland of https://flutter-review.googlesource.com/c/recipes/+/31071, but with two changes:
1) use `rmcontents` instead of `rmtree` for checkout_path
2) use a simple basic_wrap for retry, where no step is needed.

Change-Id: Ife32021474d3ff8b4790094ae2fb9ad91c7d1c6b
Bug: https://github.com/flutter/flutter/issues/105476
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/31540
Commit-Queue: Keyong Han <keyonghan@google.com>
Reviewed-by: Godofredo Contreras <godofredoc@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
diff --git a/recipe_modules/repo_util/api.py b/recipe_modules/repo_util/api.py
index 9587a70..df6aa0a 100644
--- a/recipe_modules/repo_util/api.py
+++ b/recipe_modules/repo_util/api.py
@@ -21,7 +21,6 @@
 import re
 from recipe_engine import recipe_api
 
-
 class RepoUtilApi(recipe_api.RecipeApi):
   """Provides utilities to work with flutter repos."""
 
@@ -50,10 +49,12 @@
       # Ensure depot tools is in the path to prevent problems with vpython not
       # being found after a failure.
       with self.m.depot_tools.on_path():
-        self.m.file.rmtree('Clobber cache', checkout_path)
-        self.m.file.rmtree(
-            'Clobber git cache', self.m.path['cache'].join('git')
-        )
+        if self.m.path.exists(checkout_path):
+          self.m.file.rmcontents('Clobber cache', checkout_path)
+        git_cache_path = self.m.path['cache'].join('git')
+        self.m.path.mock_add_directory(git_cache_path)
+        if self.m.path.exists(git_cache_path):
+          self.m.file.rmtree('Clobber git cache', git_cache_path)
         self.m.file.ensure_directory('Ensure checkout cache', checkout_path)
 
     # Inner function to execute code a second time in case of failure.
@@ -80,7 +81,10 @@
             self.m.gclient.c = src_cfg
             self.m.gclient.c.got_revision_mapping['src/flutter'
                                                  ] = 'got_engine_revision'
-            self.m.bot_update.ensure_checkout()
+            step_result = self.m.bot_update.ensure_checkout()
+            if ('got_revision' in step_result.presentation.properties and
+                step_result.presentation.properties['got_revision'] == 'BOT_UPDATE_NO_REV_FOUND'):
+              raise self.m.step.StepFailure('BOT_UPDATE_NO_REV_FOUND')
             self.m.gclient.runhooks()
           except:
             # On any exception, clean up the cache and raise
@@ -88,7 +92,7 @@
             raise
 
     # Some outlier GoB mirror jobs can take >250secs.
-    self.m.retry.wrap(
+    self.m.retry.basic_wrap(
         _InnerCheckout,
         step_name='Checkout source',
         sleep=10.0,
@@ -122,10 +126,12 @@
       # Ensure depot tools is in the path to prevent problems with vpython not
       # being found after a failure.
       with self.m.depot_tools.on_path():
-        self.m.file.rmtree('Clobber cache', checkout_path)
-        self.m.file.rmtree(
-            'Clobber git cache', self.m.path['cache'].join('git')
-        )
+        if self.m.path.exists(checkout_path):
+          self.m.file.rmcontents('Clobber cache', checkout_path)
+        git_cache_path = self.m.path['cache'].join('git')
+        self.m.path.mock_add_directory(git_cache_path)
+        if self.m.path.exists(git_cache_path):
+          self.m.file.rmtree('Clobber git cache', git_cache_path)
         self.m.file.ensure_directory('Ensure checkout cache', checkout_path)
 
     # Inner function to execute code a second time in case of failure.
@@ -165,7 +171,7 @@
             raise
 
     # Some outlier GoB mirror jobs can take >250secs.
-    self.m.retry.wrap(
+    self.m.retry.basic_wrap(
         _InnerCheckout,
         step_name='Checkout source',
         sleep=10.0,
diff --git a/recipe_modules/repo_util/examples/full.expected/basic.json b/recipe_modules/repo_util/examples/full.expected/basic.json
index 5b5ade3..7710cc1 100644
--- a/recipe_modules/repo_util/examples/full.expected/basic.json
+++ b/recipe_modules/repo_util/examples/full.expected/basic.json
@@ -704,30 +704,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "rmtree",
-      "[START_DIR]/engine"
-    ],
-    "env_suffixes": {
-      "DEPOT_TOOLS_UPDATE": [
-        "0"
-      ],
-      "PATH": [
-        "RECIPE_REPO[depot_tools]"
-      ]
-    },
-    "infra_step": true,
-    "name": "Checkout source code.Clobber cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "rmtree",
       "[CACHE]/git"
     ],
     "env_suffixes": {
diff --git a/recipe_modules/repo_util/examples/full.expected/bot_update.json b/recipe_modules/repo_util/examples/full.expected/bot_update.json
index 2f2b356..05fa9ac 100644
--- a/recipe_modules/repo_util/examples/full.expected/bot_update.json
+++ b/recipe_modules/repo_util/examples/full.expected/bot_update.json
@@ -576,30 +576,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "rmtree",
-      "[START_DIR]/engine"
-    ],
-    "env_suffixes": {
-      "DEPOT_TOOLS_UPDATE": [
-        "0"
-      ],
-      "PATH": [
-        "RECIPE_REPO[depot_tools]"
-      ]
-    },
-    "infra_step": true,
-    "name": "Checkout source code.Clobber cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "rmtree",
       "[CACHE]/git"
     ],
     "env_suffixes": {
diff --git a/recipe_modules/repo_util/examples/full.expected/first_bot_update_failed.json b/recipe_modules/repo_util/examples/full.expected/first_bot_update_failed.json
index 51f45e6..17d565e 100644
--- a/recipe_modules/repo_util/examples/full.expected/first_bot_update_failed.json
+++ b/recipe_modules/repo_util/examples/full.expected/first_bot_update_failed.json
@@ -579,30 +579,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "rmtree",
-      "[START_DIR]/engine"
-    ],
-    "env_suffixes": {
-      "DEPOT_TOOLS_UPDATE": [
-        "0"
-      ],
-      "PATH": [
-        "RECIPE_REPO[depot_tools]"
-      ]
-    },
-    "infra_step": true,
-    "name": "Checkout source code.Clobber cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "rmtree",
       "[CACHE]/git"
     ],
     "env_suffixes": {
@@ -732,7 +708,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[START_DIR]/engine"
     ],
     "cwd": "[START_DIR]/engine",
@@ -747,7 +723,7 @@
       ]
     },
     "infra_step": true,
-    "name": "Checkout source code.Clobber cache (2)",
+    "name": "Checkout source code.Clobber cache",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
@@ -810,29 +786,184 @@
   },
   {
     "cmd": [],
-    "name": "RECIPE CRASH (Uncaught exception)",
+    "name": "Checkout source code (2)"
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmcontents",
+      "[START_DIR]/engine"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code (2).Clobber cache",
     "~followup_annotations": [
-      "@@@STEP_EXCEPTION@@@",
-      "The recipe has crashed at point 'Uncaught exception'!",
-      "",
-      "Traceback (most recent call last):",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/examples/full.py\", line 33, in RunSteps",
-      "    api.repo_util.engine_checkout(api.path['start_dir'].join('engine'), {}, {})",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 91, in engine_checkout",
-      "    self.m.retry.wrap(",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/retry/api.py\", line 88, in wrap",
-      "    step = self.m.step.active_result",
-      "  File \"RECIPE_REPO[recipe_engine]/recipe_modules/step/api.py\", in active_result",
-      "    return self.step_client.previous_step_result()",
-      "  File \"RECIPE_REPO[recipe_engine]/recipe_engine/recipe_api.py\", in previous_step_result",
-      "    raise ValueError(",
-      "ValueError('No steps have been run yet, and you are asking for a previous step result.')"
+      "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "failure": {
-      "humanReason": "Uncaught Exception: ValueError('No steps have been run yet, and you are asking for a previous step result.')"
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmtree",
+      "[CACHE]/git"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
     },
+    "infra_step": true,
+    "name": "Checkout source code (2).Clobber git cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/engine"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code (2).Ensure checkout cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py",
+      "--spec-path",
+      "cache_dir = '[CACHE]/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': False, 'name': 'src/flutter', 'url': 'https://github.com/flutter/engine'}]",
+      "--revision_mapping_file",
+      "{\"got_engine_revision\": \"src/flutter\"}",
+      "--git-cache-dir",
+      "[CACHE]/git",
+      "--cleanup-dir",
+      "[CLEANUP]/bot_update",
+      "--output_json",
+      "/path/to/tmp/json",
+      "--revision",
+      "src/flutter@refs/pull/1/head",
+      "--refs",
+      "refs/pull/1/head"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env": {
+      "DEPOT_TOOLS_COLLECT_METRICS": "0",
+      "GIT_HTTP_LOW_SPEED_LIMIT": "102400",
+      "GIT_HTTP_LOW_SPEED_TIME": "1800"
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0",
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code (2).bot_update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@Some step text@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"did_run\": true, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"fixed_revisions\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"src/flutter\": \"refs/pull/1/head\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"manifest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"src/flutter\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"repository\": \"https://fake.org/src/flutter.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"revision\": \"a63681edc0f69a72604596b16c7986513e809995\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"patch_failure\": false, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"patch_root\": \"src/flutter\", @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_engine_revision\": \"a63681edc0f69a72604596b16c7986513e809995\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_engine_revision_cp\": \"refs/pull/1/head@{#84512}\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_revision\": \"9221bca00ddbd888260084def81f09543281b952\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"root\": \"src/flutter\", @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"source_manifest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"directories\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"src/flutter\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"git_checkout\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"repo_url\": \"https://fake.org/src/flutter.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"revision\": \"a63681edc0f69a72604596b16c7986513e809995\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"version\": 0@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"step_text\": \"Some step text\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@SET_BUILD_PROPERTY@got_engine_revision@\"a63681edc0f69a72604596b16c7986513e809995\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_engine_revision_cp@\"refs/pull/1/head@{#84512}\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"9221bca00ddbd888260084def81f09543281b952\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_REPO[depot_tools]/gclient.py",
+      "runhooks"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "name": "Checkout source code (2).gclient runhooks",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
     "name": "$result"
   }
 ]
\ No newline at end of file
diff --git a/recipe_modules/repo_util/examples/full.expected/first_bot_update_revision_not_found.json b/recipe_modules/repo_util/examples/full.expected/first_bot_update_revision_not_found.json
new file mode 100644
index 0000000..cc1ca0d
--- /dev/null
+++ b/recipe_modules/repo_util/examples/full.expected/first_bot_update_revision_not_found.json
@@ -0,0 +1,938 @@
+[
+  {
+    "cmd": [],
+    "name": "Checkout flutter/flutter"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[START_DIR]/flutter",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/flutter"
+    ],
+    "name": "Checkout flutter/flutter.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "master",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "name": "Checkout flutter/flutter.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Checkout flutter/engine"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[START_DIR]/engine",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/engine"
+    ],
+    "name": "Checkout flutter/engine.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "main",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "name": "Checkout flutter/engine.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "infra_step": true,
+    "name": "Checkout flutter/engine.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "infra_step": true,
+    "name": "Checkout flutter/engine.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "infra_step": true,
+    "name": "Checkout flutter/engine.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "infra_step": true,
+    "name": "Checkout flutter/engine.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "infra_step": true,
+    "name": "Checkout flutter/engine.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Checkout flutter/cocoon"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[START_DIR]/cocoon",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/cocoon"
+    ],
+    "name": "Checkout flutter/cocoon.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "main",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Checkout flutter/packages"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[START_DIR]/packages",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/packages"
+    ],
+    "name": "Checkout flutter/packages.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "main",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[START_DIR]/packages",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "name": "Checkout flutter/packages.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/packages",
+    "infra_step": true,
+    "name": "Checkout flutter/packages.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/packages",
+    "infra_step": true,
+    "name": "Checkout flutter/packages.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/packages",
+    "infra_step": true,
+    "name": "Checkout flutter/packages.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[START_DIR]/packages",
+    "infra_step": true,
+    "name": "Checkout flutter/packages.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[START_DIR]/packages",
+    "infra_step": true,
+    "name": "Checkout flutter/packages.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Checkout flutter/flutter (2)"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[START_DIR]/flutter",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/flutter"
+    ],
+    "name": "Checkout flutter/flutter (2).git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "beta",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "name": "Checkout flutter/flutter (2).git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter (2).git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter (2).read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter (2).git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter (2).submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "Checkout flutter/flutter (2).submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/flutter",
+    "infra_step": true,
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [],
+    "name": "Checkout source code",
+    "~followup_annotations": [
+      "@@@STEP_FAILURE@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmtree",
+      "[CACHE]/git"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code.Clobber git cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/engine"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code.Ensure checkout cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py",
+      "--spec-path",
+      "cache_dir = '[CACHE]/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': False, 'name': 'src/flutter', 'url': 'https://github.com/flutter/engine'}]",
+      "--revision_mapping_file",
+      "{\"got_engine_revision\": \"src/flutter\"}",
+      "--git-cache-dir",
+      "[CACHE]/git",
+      "--cleanup-dir",
+      "[CLEANUP]/bot_update",
+      "--output_json",
+      "/path/to/tmp/json",
+      "--revision",
+      "src/flutter@refs/pull/1/head",
+      "--refs",
+      "refs/pull/1/head"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env": {
+      "DEPOT_TOOLS_COLLECT_METRICS": "0",
+      "GIT_HTTP_LOW_SPEED_LIMIT": "102400",
+      "GIT_HTTP_LOW_SPEED_TIME": "1800"
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0",
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code.bot_update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_revision\": \"BOT_UPDATE_NO_REV_FOUND\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"BOT_UPDATE_NO_REV_FOUND\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmcontents",
+      "[START_DIR]/engine"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0",
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code.Clobber cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmtree",
+      "[CACHE]/git"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0",
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code.Clobber git cache (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/engine"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0",
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code.Ensure checkout cache (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Checkout source code (2)"
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmcontents",
+      "[START_DIR]/engine"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code (2).Clobber cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmtree",
+      "[CACHE]/git"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code (2).Clobber git cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/engine"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code (2).Ensure checkout cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py",
+      "--spec-path",
+      "cache_dir = '[CACHE]/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': False, 'name': 'src/flutter', 'url': 'https://github.com/flutter/engine'}]",
+      "--revision_mapping_file",
+      "{\"got_engine_revision\": \"src/flutter\"}",
+      "--git-cache-dir",
+      "[CACHE]/git",
+      "--cleanup-dir",
+      "[CLEANUP]/bot_update",
+      "--output_json",
+      "/path/to/tmp/json",
+      "--revision",
+      "src/flutter@refs/pull/1/head",
+      "--refs",
+      "refs/pull/1/head"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env": {
+      "DEPOT_TOOLS_COLLECT_METRICS": "0",
+      "GIT_HTTP_LOW_SPEED_LIMIT": "102400",
+      "GIT_HTTP_LOW_SPEED_TIME": "1800"
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0",
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "Checkout source code (2).bot_update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@Some step text@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"did_run\": true, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"fixed_revisions\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"src/flutter\": \"refs/pull/1/head\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"manifest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"src/flutter\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"repository\": \"https://fake.org/src/flutter.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"revision\": \"a63681edc0f69a72604596b16c7986513e809995\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"patch_failure\": false, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"patch_root\": \"src/flutter\", @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_engine_revision\": \"a63681edc0f69a72604596b16c7986513e809995\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_engine_revision_cp\": \"refs/pull/1/head@{#84512}\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_revision\": \"9221bca00ddbd888260084def81f09543281b952\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"root\": \"src/flutter\", @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"source_manifest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"directories\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"src/flutter\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"git_checkout\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"repo_url\": \"https://fake.org/src/flutter.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"revision\": \"a63681edc0f69a72604596b16c7986513e809995\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"version\": 0@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"step_text\": \"Some step text\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@SET_BUILD_PROPERTY@got_engine_revision@\"a63681edc0f69a72604596b16c7986513e809995\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_engine_revision_cp@\"refs/pull/1/head@{#84512}\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"9221bca00ddbd888260084def81f09543281b952\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_REPO[depot_tools]/gclient.py",
+      "runhooks"
+    ],
+    "cwd": "[START_DIR]/engine",
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "name": "Checkout source code (2).gclient runhooks",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/repo_util/examples/full.expected/monorepo.json b/recipe_modules/repo_util/examples/full.expected/monorepo.json
index cc9b66f..e15369d 100644
--- a/recipe_modules/repo_util/examples/full.expected/monorepo.json
+++ b/recipe_modules/repo_util/examples/full.expected/monorepo.json
@@ -1006,7 +1006,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[START_DIR]"
     ],
     "env_suffixes": {
diff --git a/recipe_modules/repo_util/examples/full.expected/monorepo_first_bot_update_failed.json b/recipe_modules/repo_util/examples/full.expected/monorepo_first_bot_update_failed.json
index 2f19fe2..c8ea136 100644
--- a/recipe_modules/repo_util/examples/full.expected/monorepo_first_bot_update_failed.json
+++ b/recipe_modules/repo_util/examples/full.expected/monorepo_first_bot_update_failed.json
@@ -1009,7 +1009,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[START_DIR]"
     ],
     "env_suffixes": {
@@ -1266,7 +1266,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[START_DIR]"
     ],
     "env_suffixes": {
@@ -1377,29 +1377,301 @@
   },
   {
     "cmd": [],
-    "name": "RECIPE CRASH (Uncaught exception)",
+    "name": "Checkout source code (2)"
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmcontents",
+      "[START_DIR]"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout source code (2).Clobber cache",
     "~followup_annotations": [
-      "@@@STEP_EXCEPTION@@@",
-      "The recipe has crashed at point 'Uncaught exception'!",
-      "",
-      "Traceback (most recent call last):",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/examples/full.py\", line 31, in RunSteps",
-      "    api.repo_util.monorepo_checkout(api.path['start_dir'], {}, {})",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 168, in monorepo_checkout",
-      "    self.m.retry.wrap(",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/retry/api.py\", line 88, in wrap",
-      "    step = self.m.step.active_result",
-      "  File \"RECIPE_REPO[recipe_engine]/recipe_modules/step/api.py\", in active_result",
-      "    return self.step_client.previous_step_result()",
-      "  File \"RECIPE_REPO[recipe_engine]/recipe_engine/recipe_api.py\", in previous_step_result",
-      "    raise ValueError(",
-      "ValueError('No steps have been run yet, and you are asking for a previous step result.')"
+      "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "failure": {
-      "humanReason": "Uncaught Exception: ValueError('No steps have been run yet, and you are asking for a previous step result.')"
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmtree",
+      "[CACHE]/git"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
     },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout source code (2).Clobber git cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]"
+    ],
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout source code (2).Ensure checkout cache",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py",
+      "--spec-path",
+      "cache_dir = '[CACHE]/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': False, 'name': 'monorepo', 'url': 'https://dart.googlesource.com/monorepo'}]",
+      "--revision_mapping_file",
+      "{\"got_buildroot_revision\": \"engine/src\", \"got_dart_revision\": \"engine/src/third_party/dart\", \"got_engine_revision\": \"engine/src/flutter\", \"got_flutter_revision\": \"flutter\", \"got_monorepo_revision\": \"monorepo\"}",
+      "--git-cache-dir",
+      "[CACHE]/git",
+      "--cleanup-dir",
+      "[CLEANUP]/bot_update",
+      "--output_json",
+      "/path/to/tmp/json",
+      "--revision",
+      "monorepo@2d72510e447ab60a9728aeea2362d8be2cbd7789",
+      "--refs",
+      "refs/heads/main"
+    ],
+    "env": {
+      "DEPOT_TOOLS_REPORT_BUILD": "project/ci/builder/8945511751514863184",
+      "GIT_HTTP_LOW_SPEED_LIMIT": "102400",
+      "GIT_HTTP_LOW_SPEED_TIME": "1800"
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0",
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout source code (2).bot_update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@Some step text@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"did_run\": true, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"fixed_revisions\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"monorepo\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"manifest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"engine/src\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"repository\": \"https://fake.org/engine/src.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"revision\": \"851705163d0a071411a2461348b2fa0f4365dd2b\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"engine/src/flutter\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"repository\": \"https://fake.org/engine/src/flutter.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"revision\": \"8d715353df333b3d997121c3d17cfe043f0a33ee\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"engine/src/third_party/dart\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"repository\": \"https://fake.org/engine/src/third_party/dart.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"revision\": \"56b272d88fce292881d9d6a89d1a88b53f868a7f\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"flutter\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"repository\": \"https://fake.org/flutter.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"revision\": \"ff25d17873bba4bc564d8c7217280aa254ed4541\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"monorepo\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"repository\": \"https://fake.org/monorepo.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"revision\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"patch_failure\": false, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"patch_root\": \"monorepo\", @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_buildroot_revision\": \"851705163d0a071411a2461348b2fa0f4365dd2b\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_buildroot_revision_cp\": \"refs/heads/main@{#278358}\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_dart_revision\": \"56b272d88fce292881d9d6a89d1a88b53f868a7f\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_dart_revision_cp\": \"refs/heads/main@{#135384}\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_engine_revision\": \"8d715353df333b3d997121c3d17cfe043f0a33ee\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_engine_revision_cp\": \"refs/heads/main@{#14355}\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_flutter_revision\": \"ff25d17873bba4bc564d8c7217280aa254ed4541\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_flutter_revision_cp\": \"refs/heads/main@{#268536}\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_monorepo_revision\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_monorepo_revision_cp\": \"refs/heads/main@{#255931}\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_revision\": \"46cec4dbb087a7b43490e8c82b6899fa32937bd9\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"root\": \"monorepo\", @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"source_manifest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"directories\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"engine/src\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"git_checkout\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"repo_url\": \"https://fake.org/engine/src.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"revision\": \"851705163d0a071411a2461348b2fa0f4365dd2b\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"engine/src/flutter\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"git_checkout\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"repo_url\": \"https://fake.org/engine/src/flutter.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"revision\": \"8d715353df333b3d997121c3d17cfe043f0a33ee\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"engine/src/third_party/dart\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"git_checkout\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"repo_url\": \"https://fake.org/engine/src/third_party/dart.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"revision\": \"56b272d88fce292881d9d6a89d1a88b53f868a7f\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"flutter\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"git_checkout\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"repo_url\": \"https://fake.org/flutter.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"revision\": \"ff25d17873bba4bc564d8c7217280aa254ed4541\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"monorepo\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"git_checkout\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"repo_url\": \"https://fake.org/monorepo.git\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"revision\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"version\": 0@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"step_text\": \"Some step text\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@SET_BUILD_PROPERTY@got_buildroot_revision@\"851705163d0a071411a2461348b2fa0f4365dd2b\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_buildroot_revision_cp@\"refs/heads/main@{#278358}\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_dart_revision@\"56b272d88fce292881d9d6a89d1a88b53f868a7f\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_dart_revision_cp@\"refs/heads/main@{#135384}\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_engine_revision@\"8d715353df333b3d997121c3d17cfe043f0a33ee\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_engine_revision_cp@\"refs/heads/main@{#14355}\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_flutter_revision@\"ff25d17873bba4bc564d8c7217280aa254ed4541\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_flutter_revision_cp@\"refs/heads/main@{#268536}\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_monorepo_revision@\"2d72510e447ab60a9728aeea2362d8be2cbd7789\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_monorepo_revision_cp@\"refs/heads/main@{#255931}\"@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"46cec4dbb087a7b43490e8c82b6899fa32937bd9\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_REPO[depot_tools]/gclient.py",
+      "runhooks"
+    ],
+    "env": {
+      "DEPOT_TOOLS_REPORT_BUILD": "project/ci/builder/8945511751514863184"
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout source code (2).gclient runhooks",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
     "name": "$result"
   }
 ]
\ No newline at end of file
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 dc162ee..a74e0aa 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
@@ -1003,9 +1003,9 @@
       "The recipe has crashed at point 'Uncaught exception'!",
       "",
       "Traceback (most recent call last):",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/examples/full.py\", line 31, in RunSteps",
+      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/examples/full.py\", line 32, in RunSteps",
       "    api.repo_util.monorepo_checkout(api.path['start_dir'], {}, {})",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 116, in monorepo_checkout",
+      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 120, in monorepo_checkout",
       "    raise ValueError(",
       "ValueError('Input reference is not on dart.googlesource.com/monorepo')"
     ]
diff --git a/recipe_modules/repo_util/examples/full.py b/recipe_modules/repo_util/examples/full.py
index 85edb3e..f998c30 100644
--- a/recipe_modules/repo_util/examples/full.py
+++ b/recipe_modules/repo_util/examples/full.py
@@ -8,6 +8,7 @@
     'flutter/repo_util',
     'recipe_engine/buildbucket',
     'recipe_engine/context',
+    'recipe_engine/json',
     'recipe_engine/path',
     'recipe_engine/properties',
     'recipe_engine/raw_io',
@@ -70,7 +71,6 @@
       ),
       # Next line force a fail condition for the bot update
       # first execution.
-      api.expect_exception('ValueError'),
       api.step_data("Checkout source code.bot_update", retcode=1)
   )
   yield (
@@ -93,7 +93,23 @@
       ) +
       # Next line force a fail condition for the bot update
       # first execution.
-      api.expect_exception('ValueError') +
       api.step_data("Checkout source code.bot_update", retcode=1) +
       api.repo_util.flutter_environment_data()
   )
+  yield (
+      api.test(
+          'first_bot_update_revision_not_found',
+          api.properties(
+              git_url='https://github.com/flutter/engine',
+              git_ref='refs/pull/1/head'
+          )
+      ) +
+      # Next line force a fail condition for the bot update
+      # first execution.
+      api.path.exists(api.path['cache'].join('git'), api.path['start_dir'].join('engine')) +
+      api.override_step_data(
+          "Checkout source code.bot_update",
+          api.json.output({'properties': {'got_revision': 'BOT_UPDATE_NO_REV_FOUND'}}),
+          retcode=0) +
+      api.repo_util.flutter_environment_data()
+  )
diff --git a/recipe_modules/repo_util/examples/unsupported.expected/unsupported.json b/recipe_modules/repo_util/examples/unsupported.expected/unsupported.json
index 3008e39..04789ef 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 15, in RunSteps",
       "    api.repo_util.checkout('unsupported_repo', repo_dir)",
-      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 189, in checkout",
+      "  File \"RECIPE_REPO[flutter]/recipe_modules/repo_util/api.py\", line 195, 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 07af4d3..b7658d7 100644
--- a/recipe_modules/retry/api.py
+++ b/recipe_modules/retry/api.py
@@ -61,7 +61,7 @@
       retriable_codes='any',
       **kwargs
   ):
-    """Retry wrapped function with exponential backoff.
+    """Retry wrapped function which needs step support.
     Args:
         step_name (str): Name of the step.
         func (callable): A function that performs the action that should be
@@ -92,3 +92,31 @@
           raise
         self.m.time.sleep(sleep)
         sleep *= backoff_factor
+
+  def basic_wrap(
+        self,
+        func,
+        max_attempts=3,
+        sleep=5.0,
+        backoff_factor=1.5,
+        **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.
+          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.
+      """
+      for attempt in range(max_attempts):
+        try:
+          func()
+          return
+        except self.m.step.StepFailure:
+          if attempt == max_attempts - 1:
+            raise
+          self.m.time.sleep(sleep)
+          sleep *= backoff_factor
diff --git a/recipe_modules/retry/examples/full.expected/failing_basic_wrap.json b/recipe_modules/retry/examples/full.expected/failing_basic_wrap.json
new file mode 100644
index 0000000..685d22a
--- /dev/null
+++ b/recipe_modules/retry/examples/full.expected/failing_basic_wrap.json
@@ -0,0 +1,53 @@
+[
+  {
+    "cmd": [
+      "echo",
+      "hello",
+      ">",
+      "/path/to/tmp/",
+      ";",
+      "echo",
+      "hello",
+      ">",
+      "/path/to/tmp/"
+    ],
+    "name": "test: Run FEMU Test Suite",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@syslog@failure@@@",
+      "@@@STEP_LOG_END@syslog@@@",
+      "@@@STEP_LOG_LINE@emulator_log@@@@",
+      "@@@STEP_LOG_END@emulator_log@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "ls",
+      "-la"
+    ],
+    "name": "test: mytest"
+  },
+  {
+    "cmd": [
+      "ls",
+      "-a"
+    ],
+    "name": "test: mytest_func"
+  },
+  {
+    "cmd": [
+      "ls",
+      "-a"
+    ],
+    "name": "test: mytest_func_basic",
+    "~followup_annotations": [
+      "@@@STEP_FAILURE@@@"
+    ]
+  },
+  {
+    "failure": {
+      "failure": {},
+      "humanReason": "Step('test: mytest_func_basic') (retcode: 1)"
+    },
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/retry/examples/full.expected/pass_with_retries.json b/recipe_modules/retry/examples/full.expected/pass_with_retries.json
index 7511dca..26dd816 100644
--- a/recipe_modules/retry/examples/full.expected/pass_with_retries.json
+++ b/recipe_modules/retry/examples/full.expected/pass_with_retries.json
@@ -67,6 +67,23 @@
     "name": "step is flaky: test: mytest_func"
   },
   {
+    "cmd": [
+      "ls",
+      "-a"
+    ],
+    "name": "test: mytest_func_basic",
+    "~followup_annotations": [
+      "@@@STEP_FAILURE@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "ls",
+      "-a"
+    ],
+    "name": "test: mytest_func_basic (2)"
+  },
+  {
     "name": "$result"
   }
 ]
\ No newline at end of file
diff --git a/recipe_modules/retry/examples/full.expected/passing.json b/recipe_modules/retry/examples/full.expected/passing.json
index 364b0b8..9692ca4 100644
--- a/recipe_modules/retry/examples/full.expected/passing.json
+++ b/recipe_modules/retry/examples/full.expected/passing.json
@@ -34,6 +34,13 @@
     "name": "test: mytest_func"
   },
   {
+    "cmd": [
+      "ls",
+      "-a"
+    ],
+    "name": "test: mytest_func_basic"
+  },
+  {
     "name": "$result"
   }
 ]
\ No newline at end of file
diff --git a/recipe_modules/retry/examples/full.py b/recipe_modules/retry/examples/full.py
index 58a21b6..e0aff6f 100644
--- a/recipe_modules/retry/examples/full.py
+++ b/recipe_modules/retry/examples/full.py
@@ -37,10 +37,14 @@
   )
   api.retry.step('test: mytest', ['ls', '-la'], max_attempts=max_attempts)
 
-  def func():
+  def func1():
     api.step('test: mytest_func', ['ls', '-a'])
 
-  api.retry.wrap(func, step_name='test: mytest_func', max_attempts=max_attempts)
+  def func2():
+    api.step('test: mytest_func_basic', ['ls', '-a'])
+
+  api.retry.wrap(func1, step_name='test: mytest_func', max_attempts=max_attempts)
+  api.retry.basic_wrap(func2, max_attempts=max_attempts)
 
 
 def GenTests(api):
@@ -54,10 +58,17 @@
                                                      'test: mytest_func',
                                                      retcode=1
                                                  )
+  yield api.test('failing_basic_wrap') + api.properties(max_attempts=1
+                                                 ) + api.step_data(
+                                                     'test: mytest_func_basic',
+                                                     retcode=1
+                                                 )
   yield api.test('pass_with_retries') + api.properties(
       max_attempts=2
   ) + api.step_data(
       'test: mytest', retcode=1
   ) + api.step_data(
       'test: mytest_func', retcode=1
+  ) + api.step_data(
+      'test: mytest_func_basic', retcode=1
   )
diff --git a/recipes/engine/engine.expected/clobber.json b/recipes/engine/engine.expected/clobber.json
index ea2135e..b27781b 100644
--- a/recipes/engine/engine.expected/clobber.json
+++ b/recipes/engine/engine.expected/clobber.json
@@ -195,7 +195,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine.expected/experimental.json b/recipes/engine/engine.expected/experimental.json
index f7b9d0c..becbc05 100644
--- a/recipes/engine/engine.expected/experimental.json
+++ b/recipes/engine/engine.expected/experimental.json
@@ -195,7 +195,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine.expected/experimental_upload.json b/recipes/engine/engine.expected/experimental_upload.json
index de75be9..52ad01d 100644
--- a/recipes/engine/engine.expected/experimental_upload.json
+++ b/recipes/engine/engine.expected/experimental_upload.json
@@ -195,7 +195,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/clobber.json b/recipes/engine/engine_arm.expected/clobber.json
index b04ea5b..5972c89 100644
--- a/recipes/engine/engine_arm.expected/clobber.json
+++ b/recipes/engine/engine_arm.expected/clobber.json
@@ -132,7 +132,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/experimental.json b/recipes/engine/engine_arm.expected/experimental.json
index 63392d6..f4fb51d 100644
--- a/recipes/engine/engine_arm.expected/experimental.json
+++ b/recipes/engine/engine_arm.expected/experimental.json
@@ -132,7 +132,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/experimental_upload.json b/recipes/engine/engine_arm.expected/experimental_upload.json
index 079fee9..99519db 100644
--- a/recipes/engine/engine_arm.expected/experimental_upload.json
+++ b/recipes/engine/engine_arm.expected/experimental_upload.json
@@ -132,7 +132,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/gcloud_pubsub_failure.json b/recipes/engine/engine_arm.expected/gcloud_pubsub_failure.json
index c05e8e5..762bee2 100644
--- a/recipes/engine/engine_arm.expected/gcloud_pubsub_failure.json
+++ b/recipes/engine/engine_arm.expected/gcloud_pubsub_failure.json
@@ -132,7 +132,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/linux.json b/recipes/engine/engine_arm.expected/linux.json
index afff9e1..6658008 100644
--- a/recipes/engine/engine_arm.expected/linux.json
+++ b/recipes/engine/engine_arm.expected/linux.json
@@ -132,7 +132,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/linux_upload.json b/recipes/engine/engine_arm.expected/linux_upload.json
index dea0541..60b0148 100644
--- a/recipes/engine/engine_arm.expected/linux_upload.json
+++ b/recipes/engine/engine_arm.expected/linux_upload.json
@@ -132,7 +132,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/mac.json b/recipes/engine/engine_arm.expected/mac.json
index 05f96a9..c76cd90 100644
--- a/recipes/engine/engine_arm.expected/mac.json
+++ b/recipes/engine/engine_arm.expected/mac.json
@@ -171,7 +171,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/mac_upload.json b/recipes/engine/engine_arm.expected/mac_upload.json
index 05f96a9..c76cd90 100644
--- a/recipes/engine/engine_arm.expected/mac_upload.json
+++ b/recipes/engine/engine_arm.expected/mac_upload.json
@@ -171,7 +171,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/pull_request.json b/recipes/engine/engine_arm.expected/pull_request.json
index b04ea5b..5972c89 100644
--- a/recipes/engine/engine_arm.expected/pull_request.json
+++ b/recipes/engine/engine_arm.expected/pull_request.json
@@ -132,7 +132,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/win.json b/recipes/engine/engine_arm.expected/win.json
index 27b819b..45fef9d 100644
--- a/recipes/engine/engine_arm.expected/win.json
+++ b/recipes/engine/engine_arm.expected/win.json
@@ -108,7 +108,7 @@
       "RECIPE_MODULE[recipe_engine::file]\\resources\\fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]\\builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_arm.expected/win_upload.json b/recipes/engine/engine_arm.expected/win_upload.json
index 27b819b..45fef9d 100644
--- a/recipes/engine/engine_arm.expected/win_upload.json
+++ b/recipes/engine/engine_arm.expected/win_upload.json
@@ -108,7 +108,7 @@
       "RECIPE_MODULE[recipe_engine::file]\\resources\\fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]\\builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_builder.expected/Schedule two builds one with goma and one without.json b/recipes/engine/engine_builder.expected/Schedule two builds one with goma and one without.json
index 0e47b92..c013b05 100644
--- a/recipes/engine/engine_builder.expected/Schedule two builds one with goma and one without.json
+++ b/recipes/engine/engine_builder.expected/Schedule two builds one with goma and one without.json
@@ -35,42 +35,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "rmtree",
-      "[CACHE]/builder"
-    ],
-    "env_suffixes": {
-      "DEPOT_TOOLS_UPDATE": [
-        "0"
-      ],
-      "PATH": [
-        "RECIPE_REPO[depot_tools]"
-      ]
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "flutter:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "Checkout source code.Clobber cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "rmtree",
       "[CACHE]/git"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_license.expected/linux.json b/recipes/engine/engine_license.expected/linux.json
index 06595fd..c30aaaf 100644
--- a/recipes/engine/engine_license.expected/linux.json
+++ b/recipes/engine/engine_license.expected/linux.json
@@ -195,7 +195,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_lint.expected/linux.json b/recipes/engine/engine_lint.expected/linux.json
index 7f51530..2c80aae 100644
--- a/recipes/engine/engine_lint.expected/linux.json
+++ b/recipes/engine/engine_lint.expected/linux.json
@@ -170,7 +170,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_lint.expected/mac.json b/recipes/engine/engine_lint.expected/mac.json
index 575a85a..46a15a5 100644
--- a/recipes/engine/engine_lint.expected/mac.json
+++ b/recipes/engine/engine_lint.expected/mac.json
@@ -209,7 +209,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_metrics.expected/basic_upload_metrics_False.json b/recipes/engine/engine_metrics.expected/basic_upload_metrics_False.json
index 4dcaef1..edf8447 100644
--- a/recipes/engine/engine_metrics.expected/basic_upload_metrics_False.json
+++ b/recipes/engine/engine_metrics.expected/basic_upload_metrics_False.json
@@ -23,30 +23,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "rmtree",
-      "[CACHE]/builder"
-    ],
-    "env_suffixes": {
-      "DEPOT_TOOLS_UPDATE": [
-        "0"
-      ],
-      "PATH": [
-        "RECIPE_REPO[depot_tools]"
-      ]
-    },
-    "infra_step": true,
-    "name": "Checkout source code.Clobber cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "rmtree",
       "[CACHE]/git"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_metrics.expected/basic_upload_metrics_True.json b/recipes/engine/engine_metrics.expected/basic_upload_metrics_True.json
index d4b3bde..aab7b07 100644
--- a/recipes/engine/engine_metrics.expected/basic_upload_metrics_True.json
+++ b/recipes/engine/engine_metrics.expected/basic_upload_metrics_True.json
@@ -23,30 +23,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "rmtree",
-      "[CACHE]/builder"
-    ],
-    "env_suffixes": {
-      "DEPOT_TOOLS_UPDATE": [
-        "0"
-      ],
-      "PATH": [
-        "RECIPE_REPO[depot_tools]"
-      ]
-    },
-    "infra_step": true,
-    "name": "Checkout source code.Clobber cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "rmtree",
       "[CACHE]/git"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_unopt.expected/linux.json b/recipes/engine/engine_unopt.expected/linux.json
index f891973..6aaf685 100644
--- a/recipes/engine/engine_unopt.expected/linux.json
+++ b/recipes/engine/engine_unopt.expected/linux.json
@@ -195,7 +195,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_unopt.expected/linux_lto.json b/recipes/engine/engine_unopt.expected/linux_lto.json
index 6b75f64..62703f9 100644
--- a/recipes/engine/engine_unopt.expected/linux_lto.json
+++ b/recipes/engine/engine_unopt.expected/linux_lto.json
@@ -195,7 +195,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_unopt.expected/mac.json b/recipes/engine/engine_unopt.expected/mac.json
index f0acc18..de099cc 100644
--- a/recipes/engine/engine_unopt.expected/mac.json
+++ b/recipes/engine/engine_unopt.expected/mac.json
@@ -234,7 +234,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_unopt.expected/mac_lto.json b/recipes/engine/engine_unopt.expected/mac_lto.json
index f0acc18..de099cc 100644
--- a/recipes/engine/engine_unopt.expected/mac_lto.json
+++ b/recipes/engine/engine_unopt.expected/mac_lto.json
@@ -234,7 +234,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_unopt.expected/win.json b/recipes/engine/engine_unopt.expected/win.json
index 643b536..b813030 100644
--- a/recipes/engine/engine_unopt.expected/win.json
+++ b/recipes/engine/engine_unopt.expected/win.json
@@ -295,7 +295,7 @@
       "RECIPE_MODULE[recipe_engine::file]\\resources\\fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]\\builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/engine_unopt.expected/win_lto.json b/recipes/engine/engine_unopt.expected/win_lto.json
index c9f2c3b..eb22ce3 100644
--- a/recipes/engine/engine_unopt.expected/win_lto.json
+++ b/recipes/engine/engine_unopt.expected/win_lto.json
@@ -295,7 +295,7 @@
       "RECIPE_MODULE[recipe_engine::file]\\resources\\fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]\\builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/framework_smoke.expected/basic.json b/recipes/engine/framework_smoke.expected/basic.json
index caf28cc..e082941 100644
--- a/recipes/engine/framework_smoke.expected/basic.json
+++ b/recipes/engine/framework_smoke.expected/basic.json
@@ -38,7 +38,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine.expected/linux-post-submit.json b/recipes/engine/web_engine.expected/linux-post-submit.json
index 81fa141..7ccfc59 100644
--- a/recipes/engine/web_engine.expected/linux-post-submit.json
+++ b/recipes/engine/web_engine.expected/linux-post-submit.json
@@ -84,7 +84,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine.expected/linux-pre-submit.json b/recipes/engine/web_engine.expected/linux-pre-submit.json
index 9d6ade7..102f28b 100644
--- a/recipes/engine/web_engine.expected/linux-pre-submit.json
+++ b/recipes/engine/web_engine.expected/linux-pre-submit.json
@@ -97,7 +97,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine.expected/mac-post-submit-with-xcode.json b/recipes/engine/web_engine.expected/mac-post-submit-with-xcode.json
index f9cd7aa..ef1eab8 100644
--- a/recipes/engine/web_engine.expected/mac-post-submit-with-xcode.json
+++ b/recipes/engine/web_engine.expected/mac-post-submit-with-xcode.json
@@ -99,7 +99,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine.expected/mac-post-submit.json b/recipes/engine/web_engine.expected/mac-post-submit.json
index d0a8ac3..acc7d5d 100644
--- a/recipes/engine/web_engine.expected/mac-post-submit.json
+++ b/recipes/engine/web_engine.expected/mac-post-submit.json
@@ -99,7 +99,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine.expected/windows-post-submit.json b/recipes/engine/web_engine.expected/windows-post-submit.json
index 2994078..ad1b970 100644
--- a/recipes/engine/web_engine.expected/windows-post-submit.json
+++ b/recipes/engine/web_engine.expected/windows-post-submit.json
@@ -140,7 +140,7 @@
       "RECIPE_MODULE[recipe_engine::file]\\resources\\fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]\\builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine_drone.expected/linux-error.json b/recipes/engine/web_engine_drone.expected/linux-error.json
index 1523331..5d682ed 100644
--- a/recipes/engine/web_engine_drone.expected/linux-error.json
+++ b/recipes/engine/web_engine_drone.expected/linux-error.json
@@ -85,7 +85,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CLEANUP]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine_drone.expected/linux-experimental.json b/recipes/engine/web_engine_drone.expected/linux-experimental.json
index 7ee0d34..2a0f88e 100644
--- a/recipes/engine/web_engine_drone.expected/linux-experimental.json
+++ b/recipes/engine/web_engine_drone.expected/linux-experimental.json
@@ -85,7 +85,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CLEANUP]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine_drone.expected/linux-firefox-integration.json b/recipes/engine/web_engine_drone.expected/linux-firefox-integration.json
index 598ecde..183a7ae 100644
--- a/recipes/engine/web_engine_drone.expected/linux-firefox-integration.json
+++ b/recipes/engine/web_engine_drone.expected/linux-firefox-integration.json
@@ -72,7 +72,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CLEANUP]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine_drone.expected/linux-post-submit.json b/recipes/engine/web_engine_drone.expected/linux-post-submit.json
index 615093f..debe08f 100644
--- a/recipes/engine/web_engine_drone.expected/linux-post-submit.json
+++ b/recipes/engine/web_engine_drone.expected/linux-post-submit.json
@@ -72,7 +72,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CLEANUP]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine_drone.expected/mac-post-submit.json b/recipes/engine/web_engine_drone.expected/mac-post-submit.json
index 7f5d4f7..f21d8b9 100644
--- a/recipes/engine/web_engine_drone.expected/mac-post-submit.json
+++ b/recipes/engine/web_engine_drone.expected/mac-post-submit.json
@@ -72,7 +72,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CLEANUP]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine_drone.expected/windows-post-submit.json b/recipes/engine/web_engine_drone.expected/windows-post-submit.json
index 0e344d6..081227b 100644
--- a/recipes/engine/web_engine_drone.expected/windows-post-submit.json
+++ b/recipes/engine/web_engine_drone.expected/windows-post-submit.json
@@ -72,7 +72,7 @@
       "RECIPE_MODULE[recipe_engine::file]\\resources\\fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CLEANUP]\\builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine/web_engine_framework.expected/linux-pre-submit.json b/recipes/engine/web_engine_framework.expected/linux-pre-submit.json
index ebc3e57..406790f 100644
--- a/recipes/engine/web_engine_framework.expected/linux-pre-submit.json
+++ b/recipes/engine/web_engine_framework.expected/linux-pre-submit.json
@@ -97,7 +97,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine_v2/builder.expected/basic.json b/recipes/engine_v2/builder.expected/basic.json
index e945483..4262dfe 100644
--- a/recipes/engine_v2/builder.expected/basic.json
+++ b/recipes/engine_v2/builder.expected/basic.json
@@ -38,7 +38,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine_v2/builder.expected/basic_custom_vars.json b/recipes/engine_v2/builder.expected/basic_custom_vars.json
index fac6624..c74d201 100644
--- a/recipes/engine_v2/builder.expected/basic_custom_vars.json
+++ b/recipes/engine_v2/builder.expected/basic_custom_vars.json
@@ -38,7 +38,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine_v2/builder.expected/basic_gcs.json b/recipes/engine_v2/builder.expected/basic_gcs.json
index d8b05d4..93d1508 100644
--- a/recipes/engine_v2/builder.expected/basic_gcs.json
+++ b/recipes/engine_v2/builder.expected/basic_gcs.json
@@ -38,7 +38,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine_v2/builder.expected/mac.json b/recipes/engine_v2/builder.expected/mac.json
index 16eea89..2278047 100644
--- a/recipes/engine_v2/builder.expected/mac.json
+++ b/recipes/engine_v2/builder.expected/mac.json
@@ -38,7 +38,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {
diff --git a/recipes/engine_v2/builder.expected/monorepo.json b/recipes/engine_v2/builder.expected/monorepo.json
index 94d3667..6a6505f 100644
--- a/recipes/engine_v2/builder.expected/monorepo.json
+++ b/recipes/engine_v2/builder.expected/monorepo.json
@@ -62,7 +62,7 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmtree",
+      "rmcontents",
       "[CACHE]/builder"
     ],
     "env_suffixes": {