Refactor package_outputs

Refactor package_outputs in the TestOptimizer so it just returns a list
of soong_zip commands to be run by build_test_suites.

Since we already have a tested implementation for running subprocesses
in build_test_suites.py there's no reason to reimplement it in
optimized_targets.py. Because any packaging will ultimately use
soong_zip to package its final outputs change the code to just do
whatever prep it needs to and return a list of soong_zip commands.

This way the code is simpler to test without requiring subprocesses and
no reimplementation of subprocess running code is necessary.

Test: atest build_test_suites_test; atest optimized_targets_test
Bug: 358215235
Change-Id: I3025aefeeb7186f537266a72d8422211ca9835ba
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index 402880c..933e43e 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -20,10 +20,8 @@
 import logging
 import os
 import pathlib
-import re
 import subprocess
 import sys
-from typing import Callable
 from build_context import BuildContext
 import optimized_targets
 
@@ -70,7 +68,7 @@
       return BuildPlan(set(self.args.extra_targets), set())
 
     build_targets = set()
-    packaging_functions = set()
+    packaging_commands = []
     for target in self.args.extra_targets:
       if self._unused_target_exclusion_enabled(
           target
@@ -86,9 +84,9 @@
           target, self.build_context, self.args
       )
       build_targets.update(target_optimizer.get_build_targets())
-      packaging_functions.add(target_optimizer.package_outputs)
+      packaging_commands.extend(target_optimizer.get_package_outputs_commands())
 
-    return BuildPlan(build_targets, packaging_functions)
+    return BuildPlan(build_targets, packaging_commands)
 
   def _unused_target_exclusion_enabled(self, target: str) -> bool:
     return (
@@ -100,7 +98,7 @@
 @dataclass(frozen=True)
 class BuildPlan:
   build_targets: set[str]
-  packaging_functions: set[Callable[..., None]]
+  packaging_commands: list[list[str]]
 
 
 def build_test_suites(argv: list[str]) -> int:
@@ -182,8 +180,11 @@
   except subprocess.CalledProcessError as e:
     raise BuildFailureError(e.returncode) from e
 
-  for packaging_function in build_plan.packaging_functions:
-    packaging_function()
+  for packaging_command in build_plan.packaging_commands:
+    try:
+      run_command(packaging_command)
+    except subprocess.CalledProcessError as e:
+      raise BuildFailureError(e.returncode) from e
 
 
 def get_top() -> pathlib.Path: