Add a download utility to the archives module.

This is to simplify downloading artifacts when we have the full gcs
path.

Bug: https://github.com/flutter/flutter/issues/81855
Change-Id: I0f83074ad86a8f4208f2c8a219f3d019681cfb8c
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/36520
Commit-Queue: Godofredo Contreras <godofredoc@google.com>
Reviewed-by: Xilai Zhang <xilaizhang@google.com>
diff --git a/recipe_modules/archives/api.py b/recipe_modules/archives/api.py
index abd1038..4c77e18 100644
--- a/recipe_modules/archives/api.py
+++ b/recipe_modules/archives/api.py
@@ -106,6 +106,18 @@
         name=path,
     )
 
+  def download(self, src, dst):
+    """Downloads a file from GCS.
+
+    Args:
+      src: A string with gcs uri to download.
+      dst: A string with the local destination for the file.
+    """
+    bucket, path = self._split_dst_parts(src)
+    self.m.gsutil.download(
+        bucket, path, dst, name="download %s" % src
+    )
+
   def engine_v2_gcs_paths(self, checkout, archive_config, bucket=DEFAULT_BUCKET):
     """Calculates engine v2 GCS paths from an archive config.
 
diff --git a/recipe_modules/archives/examples/full.expected/basic.json b/recipe_modules/archives/examples/full.expected/basic.json
index 8bf6f5c..b2e060a 100644
--- a/recipe_modules/archives/examples/full.expected/basic.json
+++ b/recipe_modules/archives/examples/full.expected/basic.json
@@ -77,6 +77,21 @@
     ]
   },
   {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "gs://flutter_archives_v2/flutter_infra_release/flutter/12345abcde12345abcde12345abcde12345abcde/android-arm-profile/artifacts.zip",
+      "[START_DIR]/out/android_profile/zip_archives/android-arm-profile/artifacts.zip"
+    ],
+    "infra_step": true,
+    "name": "gsutil download gs://flutter_archives_v2/flutter_infra_release/flutter/12345abcde12345abcde12345abcde12345abcde/android-arm-profile/artifacts.zip"
+  },
+  {
     "name": "$result"
   }
 ]
\ No newline at end of file
diff --git a/recipe_modules/archives/examples/full.expected/monorepo_gcs.json b/recipe_modules/archives/examples/full.expected/monorepo_gcs.json
index 0e68782..4902b58 100644
--- a/recipe_modules/archives/examples/full.expected/monorepo_gcs.json
+++ b/recipe_modules/archives/examples/full.expected/monorepo_gcs.json
@@ -137,6 +137,33 @@
     ]
   },
   {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "gs://flutter_archives_v2/monorepo/flutter_infra_release/flutter/12345abcde12345abcde12345abcde12345abcde/android-arm-profile/artifacts.zip",
+      "[START_DIR]/out/android_profile/zip_archives/android-arm-profile/artifacts.zip"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "gsutil download gs://flutter_archives_v2/monorepo/flutter_infra_release/flutter/12345abcde12345abcde12345abcde12345abcde/android-arm-profile/artifacts.zip"
+  },
+  {
     "name": "$result"
   }
 ]
\ No newline at end of file
diff --git a/recipe_modules/archives/examples/full.py b/recipe_modules/archives/examples/full.py
index a712ced..6609bcf 100644
--- a/recipe_modules/archives/examples/full.py
+++ b/recipe_modules/archives/examples/full.py
@@ -27,6 +27,7 @@
   }
   results = api.archives.engine_v2_gcs_paths(checkout, config)
   api.archives.upload_artifact(results[0].local, results[0].remote)
+  api.archives.download(results[0].remote, results[0].local)
 
 
 def GenTests(api):