scripts/build_linters: Detect package categories

This CL implements a feature for the build_linters script to detect and
add the category for any packages that are only given by name. This
done by parsing `equery-<board> w <package>` and taking the category
from the path to the ebuild.

BUG=b:229143726
TEST=manual testing with packages in platform2

Change-Id: Ie044b2bd32ca335708ca3a117beff1a0db2712be
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/3615562
Reviewed-by: Alex Klein <saklein@chromium.org>
Commit-Queue: Ryan Beltran <ryanbeltran@chromium.org>
Tested-by: Ryan Beltran <ryanbeltran@chromium.org>
diff --git a/scripts/lint_package.py b/scripts/lint_package.py
index 1c4d4bf..c63bbc2 100644
--- a/scripts/lint_package.py
+++ b/scripts/lint_package.py
@@ -15,11 +15,35 @@
 from chromite.lib import build_target_lib
 from chromite.lib import commandline
 from chromite.lib import cros_build_lib
+from chromite.lib import portage_util
 from chromite.lib.parser import package_info
 from chromite.service import toolchain
 from chromite.utils import file_util
 
 
+def parse_packages(board: str,
+                   packages: List[str]) -> List[package_info.PackageInfo]:
+  """Parse packages and insert the category if none is given.
+
+  Args:
+    board: board for sysroot (used with equery to detect categories if needed)
+    packages: user input package names to parse
+
+  Returns:
+    A list of parsed PackageInfo objects
+  """
+  package_infos: List[package_info.PackageInfo] = []
+  for package in packages:
+    parsed = package_info.parse(package)
+    if not parsed.category:
+      # If a category is not specified, we can get it from the ebuild path.
+      ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
+      ebuild_data = portage_util.EBuild(ebuild_path)
+      parsed = package_info.parse(ebuild_data.package)
+    package_infos.append(parsed)
+  return package_infos
+
+
 def get_arg_parser() -> commandline.ArgumentParser:
   """Creates an argument parser for this script."""
   default_board = cros_build_lib.GetDefaultBoard()
@@ -68,7 +92,7 @@
   cros_build_lib.AssertInsideChroot()
   opts = parse_args(argv)
 
-  packages = [package_info.parse(x) for x in opts.packages]
+  packages = parse_packages(opts.board, opts.packages)
   sysroot = build_target_lib.get_default_sysroot_path(opts.board)
 
   build_linter = toolchain.BuildLinter(packages, sysroot, opts.differential)