alchemist: Introduce MaybePackageDetails

This patch follows the same pattern as MaybeEBuildMetadata: introduces
an enum that allows interleaving success/failure cases of package
loading and differentiating them statically at the same time.

While this new enum allows us cleaning up a few logic, this patch
focuses on introducing it with minimal changes.

This is a pure refactoring and not supposed to change any behavior.

BUG=b:303400631
TEST=bazel test //bazel/portage/bin/alchemist:all

Change-Id: Ie0d1396c7a068b697b3e404aa8dcd287465a0b3e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/bazel/+/4982815
Reviewed-by: Maksim Ivanov <emaxx@chromium.org>
Tested-by: Shuhei Takahashi <nya@chromium.org>
Commit-Queue: Shuhei Takahashi <nya@chromium.org>
diff --git a/portage/bin/alchemist/src/analyze/restrict.rs b/portage/bin/alchemist/src/analyze/restrict.rs
index 344033f..47deb8e 100644
--- a/portage/bin/alchemist/src/analyze/restrict.rs
+++ b/portage/bin/alchemist/src/analyze/restrict.rs
@@ -32,11 +32,13 @@
     use std::{
         collections::{HashMap, HashSet},
         path::PathBuf,
+        sync::Arc,
     };
 
     use crate::{
         bash::vars::{BashValue, BashVars},
         data::Slot,
+        ebuild::metadata::{EBuildBasicData, EBuildMetadata},
     };
 
     use super::*;
@@ -47,16 +49,22 @@
             vars.insert("RESTRICT".to_owned(), value);
         }
         PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "foo/bar".to_owned(),
-            version: "1.0".parse().unwrap(),
-            vars: BashVars::new(vars),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from("/path/to/some.ebuild"),
+                    package_name: "foo/bar".to_owned(),
+                    short_package_name: "bar".to_owned(),
+                    category_name: "foo".to_owned(),
+                    version: "1.0".parse().unwrap(),
+                },
+                vars: BashVars::new(vars),
+            }),
             slot: Slot::new("0"),
             use_map,
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: PathBuf::from("/path/to/some.ebuild"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
diff --git a/portage/bin/alchemist/src/analyze/source.rs b/portage/bin/alchemist/src/analyze/source.rs
index cf7bdef..57c16c3 100644
--- a/portage/bin/alchemist/src/analyze/source.rs
+++ b/portage/bin/alchemist/src/analyze/source.rs
@@ -598,8 +598,10 @@
     use crate::bash::vars::BashVars;
     use crate::config::{ConfigNode, ConfigNodeValue, SimpleConfigSource};
     use crate::data::{Slot, Vars};
+    use crate::ebuild::metadata::{EBuildBasicData, EBuildMetadata};
     use crate::testutils::write_files;
     use std::collections::HashSet;
+    use std::sync::Arc;
 
     use tempfile::TempDir;
     use version::Version;
@@ -621,21 +623,27 @@
         )?;
 
         let package = PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "sys-libs/foo".to_owned(),
-            version: Version::try_new("0.1.0").unwrap(),
-            vars: BashVars::new(HashMap::from([
-                ("SRC_URI".to_owned(),
-                    BashValue::Scalar("https://example/f00-0.1.0.tar.gz -> foo-0.1.0.tar.gz extra? ( gs://chromeos-localmirror/foo-extra.tar.gz )".to_owned())),
-                ("RESTRICT".to_owned(),
-                    BashValue::Scalar("extra? ( mirror )".to_owned())),
-                ])),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: tmp.path().join("foo-0.1.0.ebuild"),
+                    package_name: "sys-libs/foo".to_owned(),
+                    short_package_name: "foo".to_owned(),
+                    category_name: "sys-libs".to_owned(),
+                    version: Version::try_new("0.1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::from([
+                    ("SRC_URI".to_owned(),
+                        BashValue::Scalar("https://example/f00-0.1.0.tar.gz -> foo-0.1.0.tar.gz extra? ( gs://chromeos-localmirror/foo-extra.tar.gz )".to_owned())),
+                    ("RESTRICT".to_owned(),
+                        BashValue::Scalar("extra? ( mirror )".to_owned())),
+                    ])),
+            }),
             slot: Slot::new("0"),
             use_map,
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: tmp.path().join("foo-0.1.0.ebuild"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
@@ -736,60 +744,67 @@
     #[test]
     fn cros_workon_pinned_package_with_subtree() -> Result<()> {
         let package = PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "sys-boot/libpayload".to_owned(),
-            version: Version::try_new("0.1.0")?,
-            vars: BashVars::new(HashMap::from([
-                (
-                    "CROS_WORKON_PROJECT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "chromiumos/third_party/coreboot".to_owned(),
-                        "chromiumos/platform/vboot_reference".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_LOCALNAME".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "coreboot".to_owned(),
-                        "../platform/vboot_reference".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_SUBTREE".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "payloads/libpayload src/commonlib util/kconfig util/xcompile".to_owned(),
-                        "Makefile firmware".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_COMMIT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "e71dd376a369e2351265e79e19e926594f92e604".to_owned(),
-                        "49820c727819ca566c65efa0525a8022f07cc27e".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_TREE".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "6f11773570dfaaade362374b0d0392c28cf17206".to_owned(),
-                        "5e822365b04b4690729ca6ec32935a177db97ed2".to_owned(),
-                        "514603540da793957fa87fa22df81b288fb39d0f".to_owned(),
-                        "b2307ed1e70bf1a5718afaa81217ec9504854005".to_owned(),
-                        "bc55f0377f73029f50c4c74d5936e4d7bde877c6".to_owned(),
-                        "e70ebd7c76b9f9ad44b59e3002a5c57be5b9dc12".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
-                    BashValue::IndexedArray(Vec::from(["".to_owned(), "".to_owned()])),
-                ),
-            ])),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from("/dev/null"),
+                    package_name: "sys-boot/libpayload".to_owned(),
+                    short_package_name: "libpayload".to_owned(),
+                    category_name: "sys-boot".to_owned(),
+                    version: Version::try_new("0.1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::from([
+                    (
+                        "CROS_WORKON_PROJECT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "chromiumos/third_party/coreboot".to_owned(),
+                            "chromiumos/platform/vboot_reference".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_LOCALNAME".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "coreboot".to_owned(),
+                            "../platform/vboot_reference".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_SUBTREE".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "payloads/libpayload src/commonlib util/kconfig util/xcompile"
+                                .to_owned(),
+                            "Makefile firmware".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_COMMIT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "e71dd376a369e2351265e79e19e926594f92e604".to_owned(),
+                            "49820c727819ca566c65efa0525a8022f07cc27e".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_TREE".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "6f11773570dfaaade362374b0d0392c28cf17206".to_owned(),
+                            "5e822365b04b4690729ca6ec32935a177db97ed2".to_owned(),
+                            "514603540da793957fa87fa22df81b288fb39d0f".to_owned(),
+                            "b2307ed1e70bf1a5718afaa81217ec9504854005".to_owned(),
+                            "bc55f0377f73029f50c4c74d5936e4d7bde877c6".to_owned(),
+                            "e70ebd7c76b9f9ad44b59e3002a5c57be5b9dc12".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
+                        BashValue::IndexedArray(Vec::from(["".to_owned(), "".to_owned()])),
+                    ),
+                ])),
+            }),
             slot: Slot::new("0"),
             use_map: UseMap::new(),
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: PathBuf::from("/dev/null"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
@@ -852,61 +867,67 @@
     #[test]
     fn cros_workon_pinned_package_without_subtree() -> Result<()> {
         let package = PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "sys-boot/depthcharge".to_owned(),
-            version: Version::try_new("0.1.0")?,
-            vars: BashVars::new(HashMap::from([
-                (
-                    "CROS_WORKON_PROJECT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "chromiumos/platform/depthcharge".to_owned(),
-                        "chromiumos/platform/vboot_reference".to_owned(),
-                        "chromiumos/third_party/coreboot".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_LOCALNAME".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "../platform/depthcharge".to_owned(),
-                        "../platform/vboot_reference".to_owned(),
-                        "../third_party/coreboot".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_COMMIT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "7e1e4037a9e46a9cbf502b2b20cdc9db1a84cf94".to_owned(),
-                        "52f28a4b68aa018fff3cc575610bc9c1c04a030f".to_owned(),
-                        "d5929971f3efe2e8a398c385309ca4aad110dc02".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_TREE".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "63534c063f7717bd89631830e076229c41829c17".to_owned(),
-                        "b7ba676717ca1fa2a26b1f3107afdce3be979a78".to_owned(),
-                        "5478a5900ed6376f77b84efb27677c105fc253d6".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_SUBTREE".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "".to_owned(),
-                        "".to_owned(),
-                        "".to_owned(),
-                    ])),
-                ),
-            ])),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from("/dev/null"),
+                    package_name: "sys-boot/depthcharge".to_owned(),
+                    short_package_name: "depthcharge".to_owned(),
+                    category_name: "sys-boot".to_owned(),
+                    version: Version::try_new("0.1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::from([
+                    (
+                        "CROS_WORKON_PROJECT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "chromiumos/platform/depthcharge".to_owned(),
+                            "chromiumos/platform/vboot_reference".to_owned(),
+                            "chromiumos/third_party/coreboot".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_LOCALNAME".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "../platform/depthcharge".to_owned(),
+                            "../platform/vboot_reference".to_owned(),
+                            "../third_party/coreboot".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_COMMIT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "7e1e4037a9e46a9cbf502b2b20cdc9db1a84cf94".to_owned(),
+                            "52f28a4b68aa018fff3cc575610bc9c1c04a030f".to_owned(),
+                            "d5929971f3efe2e8a398c385309ca4aad110dc02".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_TREE".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "63534c063f7717bd89631830e076229c41829c17".to_owned(),
+                            "b7ba676717ca1fa2a26b1f3107afdce3be979a78".to_owned(),
+                            "5478a5900ed6376f77b84efb27677c105fc253d6".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_SUBTREE".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "".to_owned(),
+                            "".to_owned(),
+                            "".to_owned(),
+                        ])),
+                    ),
+                ])),
+            }),
             slot: Slot::new("0"),
             use_map: UseMap::new(),
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: PathBuf::from("/dev/null"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
@@ -949,59 +970,65 @@
     #[test]
     fn cros_workon_pinned_package_with_chromite_subtree() -> Result<()> {
         let package = PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "chromeos-base/hwid_extractor".to_owned(),
-            version: Version::try_new("0.1.0")?,
-            vars: BashVars::new(HashMap::from([
-                (
-                    "CROS_WORKON_PROJECT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "chromiumos/platform/factory".to_owned(),
-                        "chromiumos/chromite".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_LOCALNAME".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "platform/factory".to_owned(),
-                        "../chromite".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_SUBTREE".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "py".to_owned(),
-                        "lib bin scripts PRESUBMIT.cfg".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_COMMIT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "e71dd376a369e2351265e79e19e926594f92e604".to_owned(),
-                        "49820c727819ca566c65efa0525a8022f07cc27e".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_TREE".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "6f11773570dfaaade362374b0d0392c28cf17206".to_owned(),
-                        "5e822365b04b4690729ca6ec32935a177db97ed2".to_owned(),
-                        "514603540da793957fa87fa22df81b288fb39d0f".to_owned(),
-                        "b2307ed1e70bf1a5718afaa81217ec9504854005".to_owned(),
-                        "bc55f0377f73029f50c4c74d5936e4d7bde877c6".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
-                    BashValue::IndexedArray(Vec::from(["".to_owned(), "".to_owned()])),
-                ),
-            ])),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from("/dev/null"),
+                    package_name: "chromeos-base/hwid_extractor".to_owned(),
+                    short_package_name: "hwid_extractor".to_owned(),
+                    category_name: "chromeos-base".to_owned(),
+                    version: Version::try_new("0.1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::from([
+                    (
+                        "CROS_WORKON_PROJECT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "chromiumos/platform/factory".to_owned(),
+                            "chromiumos/chromite".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_LOCALNAME".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "platform/factory".to_owned(),
+                            "../chromite".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_SUBTREE".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "py".to_owned(),
+                            "lib bin scripts PRESUBMIT.cfg".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_COMMIT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "e71dd376a369e2351265e79e19e926594f92e604".to_owned(),
+                            "49820c727819ca566c65efa0525a8022f07cc27e".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_TREE".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "6f11773570dfaaade362374b0d0392c28cf17206".to_owned(),
+                            "5e822365b04b4690729ca6ec32935a177db97ed2".to_owned(),
+                            "514603540da793957fa87fa22df81b288fb39d0f".to_owned(),
+                            "b2307ed1e70bf1a5718afaa81217ec9504854005".to_owned(),
+                            "bc55f0377f73029f50c4c74d5936e4d7bde877c6".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
+                        BashValue::IndexedArray(Vec::from(["".to_owned(), "".to_owned()])),
+                    ),
+                ])),
+            }),
             slot: Slot::new("0"),
             use_map: UseMap::new(),
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: PathBuf::from("/dev/null"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
@@ -1077,50 +1104,56 @@
         )?;
 
         let package = PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "chromeos-base/hwid_extractor".to_owned(),
-            version: Version::try_new("0.1.0")?,
-            vars: BashVars::new(HashMap::from([
-                (
-                    "CROS_WORKON_PROJECT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "chromiumos/platform/factory".to_owned(),
-                        "chromiumos/chromite".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_LOCALNAME".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "platform/factory".to_owned(),
-                        "../chromite".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_SUBTREE".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "py".to_owned(),
-                        "lib bin scripts PRESUBMIT.cfg".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_COMMIT".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_TREE".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
-                    BashValue::IndexedArray(Vec::from(["".to_owned(), "".to_owned()])),
-                ),
-            ])),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from("/dev/null"),
+                    package_name: "chromeos-base/hwid_extractor".to_owned(),
+                    short_package_name: "hwid_extractor".to_owned(),
+                    category_name: "chromeos-base".to_owned(),
+                    version: Version::try_new("0.1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::from([
+                    (
+                        "CROS_WORKON_PROJECT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "chromiumos/platform/factory".to_owned(),
+                            "chromiumos/chromite".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_LOCALNAME".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "platform/factory".to_owned(),
+                            "../chromite".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_SUBTREE".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "py".to_owned(),
+                            "lib bin scripts PRESUBMIT.cfg".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_COMMIT".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_TREE".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
+                        BashValue::IndexedArray(Vec::from(["".to_owned(), "".to_owned()])),
+                    ),
+                ])),
+            }),
             slot: Slot::new("0"),
             use_map: UseMap::new(),
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: PathBuf::from("/dev/null"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
@@ -1158,49 +1191,55 @@
         )?;
 
         let package = PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "sys-boot/coreboot".to_owned(),
-            version: Version::try_new("0.1.0")?,
-            vars: BashVars::new(HashMap::from([
-                (
-                    "CROS_WORKON_PROJECT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "chromiumos/third_party/coreboot".to_owned(),
-                        "chromiumos/platform/vboot_reference".to_owned(),
-                        "chromiumos/chromite".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_LOCALNAME".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "coreboot".to_owned(),
-                        "../platform/vboot_reference".to_owned(),
-                        "../../chromite".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_SUBTREE".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_COMMIT".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_TREE".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-            ])),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from("/dev/null"),
+                    package_name: "sys-boot/coreboot".to_owned(),
+                    short_package_name: "coreboot".to_owned(),
+                    category_name: "sys-boot".to_owned(),
+                    version: Version::try_new("0.1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::from([
+                    (
+                        "CROS_WORKON_PROJECT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "chromiumos/third_party/coreboot".to_owned(),
+                            "chromiumos/platform/vboot_reference".to_owned(),
+                            "chromiumos/chromite".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_LOCALNAME".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "coreboot".to_owned(),
+                            "../platform/vboot_reference".to_owned(),
+                            "../../chromite".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_SUBTREE".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_COMMIT".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_TREE".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                ])),
+            }),
             slot: Slot::new("0"),
             use_map: UseMap::new(),
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: PathBuf::from("/dev/null"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
@@ -1223,60 +1262,70 @@
 
     fn create_optional_subtree_package(use_map: UseMap) -> PackageDetails {
         PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "sys-boot/libpayload".to_owned(),
-            version: Version::try_new("0.1.0").unwrap(),
-            vars: BashVars::new(HashMap::from([
-                (
-                    "CROS_WORKON_PROJECT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "chromiumos/third_party/coreboot".to_owned(),
-                        "chromiumos/platform/vboot_reference".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_LOCALNAME".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "coreboot".to_owned(),
-                        "../platform/vboot_reference".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_SUBTREE".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "payloads/libpayload src/commonlib util/kconfig util/xcompile".to_owned(),
-                        "Makefile firmware".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_COMMIT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "e71dd376a369e2351265e79e19e926594f92e604".to_owned(),
-                        "49820c727819ca566c65efa0525a8022f07cc27e".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_TREE".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "6f11773570dfaaade362374b0d0392c28cf17206".to_owned(),
-                        "5e822365b04b4690729ca6ec32935a177db97ed2".to_owned(),
-                        "514603540da793957fa87fa22df81b288fb39d0f".to_owned(),
-                        "b2307ed1e70bf1a5718afaa81217ec9504854005".to_owned(),
-                        "bc55f0377f73029f50c4c74d5936e4d7bde877c6".to_owned(),
-                        "e70ebd7c76b9f9ad44b59e3002a5c57be5b9dc12".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
-                    BashValue::IndexedArray(Vec::from(["use coreboot".to_owned(), "".to_owned()])),
-                ),
-            ])),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from("/dev/null"),
+                    package_name: "sys-boot/libpayload".to_owned(),
+                    short_package_name: "libpayload".to_owned(),
+                    category_name: "sys-boot".to_owned(),
+                    version: Version::try_new("0.1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::from([
+                    (
+                        "CROS_WORKON_PROJECT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "chromiumos/third_party/coreboot".to_owned(),
+                            "chromiumos/platform/vboot_reference".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_LOCALNAME".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "coreboot".to_owned(),
+                            "../platform/vboot_reference".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_SUBTREE".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "payloads/libpayload src/commonlib util/kconfig util/xcompile"
+                                .to_owned(),
+                            "Makefile firmware".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_COMMIT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "e71dd376a369e2351265e79e19e926594f92e604".to_owned(),
+                            "49820c727819ca566c65efa0525a8022f07cc27e".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_TREE".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "6f11773570dfaaade362374b0d0392c28cf17206".to_owned(),
+                            "5e822365b04b4690729ca6ec32935a177db97ed2".to_owned(),
+                            "514603540da793957fa87fa22df81b288fb39d0f".to_owned(),
+                            "b2307ed1e70bf1a5718afaa81217ec9504854005".to_owned(),
+                            "bc55f0377f73029f50c4c74d5936e4d7bde877c6".to_owned(),
+                            "e70ebd7c76b9f9ad44b59e3002a5c57be5b9dc12".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "use coreboot".to_owned(),
+                            "".to_owned(),
+                        ])),
+                    ),
+                ])),
+            }),
             slot: Slot::new("0"),
             use_map,
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: PathBuf::from("/dev/null"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
@@ -1390,53 +1439,59 @@
         )?;
 
         let package = PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "sys-boot/depthcharge".to_owned(),
-            version: Version::try_new("9999")?,
-            vars: BashVars::new(HashMap::from([
-                (
-                    "CROS_WORKON_PROJECT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "chromiumos/platform/depthcharge".to_owned(),
-                        "chromiumos/platform/vboot_reference".to_owned(),
-                        "chromiumos/third_party/coreboot".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_LOCALNAME".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "../platform/depthcharge".to_owned(),
-                        "../platform/vboot_reference".to_owned(),
-                        "../third_party/coreboot".to_owned(),
-                    ])),
-                ),
-                (
-                    "CROS_WORKON_COMMIT".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_TREE".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_SUBTREE".to_owned(),
-                    BashValue::Scalar("".to_owned()),
-                ),
-                (
-                    "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
-                    BashValue::IndexedArray(Vec::from([
-                        "".to_owned(),
-                        "".to_owned(),
-                        "".to_owned(),
-                    ])),
-                ),
-            ])),
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from("/dev/null"),
+                    package_name: "sys-boot/depthcharge".to_owned(),
+                    short_package_name: "depthcharge".to_owned(),
+                    category_name: "sys-boot".to_owned(),
+                    version: Version::try_new("0.1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::from([
+                    (
+                        "CROS_WORKON_PROJECT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "chromiumos/platform/depthcharge".to_owned(),
+                            "chromiumos/platform/vboot_reference".to_owned(),
+                            "chromiumos/third_party/coreboot".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_LOCALNAME".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "../platform/depthcharge".to_owned(),
+                            "../platform/vboot_reference".to_owned(),
+                            "../third_party/coreboot".to_owned(),
+                        ])),
+                    ),
+                    (
+                        "CROS_WORKON_COMMIT".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_TREE".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_SUBTREE".to_owned(),
+                        BashValue::Scalar("".to_owned()),
+                    ),
+                    (
+                        "CROS_WORKON_OPTIONAL_CHECKOUT".to_owned(),
+                        BashValue::IndexedArray(Vec::from([
+                            "".to_owned(),
+                            "".to_owned(),
+                            "".to_owned(),
+                        ])),
+                    ),
+                ])),
+            }),
             slot: Slot::new("0"),
             use_map: UseMap::new(),
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: PathBuf::from("/dev/null"),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
diff --git a/portage/bin/alchemist/src/bin/alchemist/generate_repo/common.rs b/portage/bin/alchemist/src/bin/alchemist/generate_repo/common.rs
index 74f90a7..9e6304e 100644
--- a/portage/bin/alchemist/src/bin/alchemist/generate_repo/common.rs
+++ b/portage/bin/alchemist/src/bin/alchemist/generate_repo/common.rs
@@ -9,7 +9,7 @@
         dependency::PackageDependencies,
         source::{PackageDistSource, PackageSources},
     },
-    ebuild::{PackageDetails, PackageMetadataError},
+    ebuild::{PackageDetails, PackageLoadError},
     repository::RepositorySet,
 };
 use anyhow::Result;
@@ -155,7 +155,7 @@
 
 #[derive(Clone, Debug)]
 pub enum PackageError {
-    PackageMetadataError(PackageMetadataError),
+    PackageMetadataError(PackageLoadError),
     PackageAnalysisError(PackageAnalysisError),
 }
 
@@ -174,7 +174,7 @@
     }
     pub fn ebuild(&self) -> &Path {
         match self {
-            Self::PackageMetadataError(p) => &p.ebuild,
+            Self::PackageMetadataError(p) => &p.ebuild_path,
             Self::PackageAnalysisError(p) => &p.details.ebuild_path,
         }
     }
diff --git a/portage/bin/alchemist/src/bin/alchemist/generate_repo/deps.rs b/portage/bin/alchemist/src/bin/alchemist/generate_repo/deps.rs
index 31678f0..47ba4e0 100644
--- a/portage/bin/alchemist/src/bin/alchemist/generate_repo/deps.rs
+++ b/portage/bin/alchemist/src/bin/alchemist/generate_repo/deps.rs
@@ -125,7 +125,11 @@
 
 #[cfg(test)]
 mod tests {
-    use std::collections::{HashMap, HashSet};
+    use std::{
+        collections::{HashMap, HashSet},
+        path::PathBuf,
+        sync::Arc,
+    };
 
     use alchemist::{
         analyze::{
@@ -134,7 +138,10 @@
         },
         bash::vars::BashVars,
         data::{Slot, UseMap},
-        ebuild::PackageDetails,
+        ebuild::{
+            metadata::{EBuildBasicData, EBuildMetadata},
+            PackageDetails,
+        },
     };
     use pretty_assertions::assert_eq;
     use url::Url;
@@ -192,33 +199,33 @@
             install_host_deps: vec![],
         };
 
-        let details_prototype = PackageDetails {
-            repo_name: "baz".to_owned(),
-            package_name: "prototype".to_owned(),
-            version: Version::try_new("1.0").unwrap(),
-            vars: BashVars::new(HashMap::new()),
+        let make_details = |short_package_name: &str| PackageDetails {
+            metadata: Arc::new(EBuildMetadata {
+                basic_data: EBuildBasicData {
+                    repo_name: "baz".to_owned(),
+                    ebuild_path: PathBuf::from(format!(
+                        "/somewhere/sys-apps/{short_package_name}-1.0.ebuild"
+                    )),
+                    package_name: format!("sys-apps/{short_package_name}"),
+                    short_package_name: short_package_name.to_owned(),
+                    category_name: "sys-apps".to_owned(),
+                    version: Version::try_new("1.0").unwrap(),
+                },
+                vars: BashVars::new(HashMap::new()),
+            }),
             slot: Slot::new("0"),
             use_map: UseMap::new(),
             accepted: true,
             stable: true,
             masked: false,
-            ebuild_path: "/somewhere/sys-apps/prototype-1.0.ebuild".into(),
             inherited: HashSet::new(),
             inherit_paths: vec![],
             direct_build_target: None,
         };
 
-        let mut details1 = details_prototype.clone();
-        details1.package_name = "sys-apps/p1".to_owned();
-        details1.ebuild_path = "/somewhere/sys-apps/p1-1.0.ebuild".into();
-
-        let mut details2 = details_prototype.clone();
-        details2.package_name = "sys-apps/p2".to_owned();
-        details2.ebuild_path = "/somewhere/sys-apps/p2-1.0.ebuild".into();
-
-        let mut details3 = details_prototype.clone();
-        details3.package_name = "sys-apps/p3".to_owned();
-        details3.ebuild_path = "/somewhere/sys-apps/p3-1.0.ebuild".into();
+        let details1 = make_details("p1");
+        let details2 = make_details("p2");
+        let details3 = make_details("p3");
 
         let packages = vec![
             Package {
diff --git a/portage/bin/alchemist/src/bin/alchemist/generate_repo/mod.rs b/portage/bin/alchemist/src/bin/alchemist/generate_repo/mod.rs
index 2f9d3fd..65ffe35 100644
--- a/portage/bin/alchemist/src/bin/alchemist/generate_repo/mod.rs
+++ b/portage/bin/alchemist/src/bin/alchemist/generate_repo/mod.rs
@@ -23,7 +23,7 @@
     },
     config::{bundle::ConfigBundle, ProvidedPackage},
     dependency::{package::PackageAtom, Predicate},
-    ebuild::{CachedPackageLoader, PackageDetails, PackageMetadataError},
+    ebuild::{CachedPackageLoader, MaybePackageDetails, PackageDetails, PackageLoadError},
     fakechroot::PathTranslator,
     repository::RepositorySet,
     resolver::PackageResolver,
@@ -56,7 +56,7 @@
 fn evaluate_all_packages(
     repos: &RepositorySet,
     loader: &CachedPackageLoader,
-) -> Result<(Vec<Arc<PackageDetails>>, Vec<Arc<PackageMetadataError>>)> {
+) -> Result<(Vec<Arc<PackageDetails>>, Vec<Arc<PackageLoadError>>)> {
     let ebuild_paths = repos.find_all_ebuilds()?;
 
     // Evaluate packages in parallel.
@@ -67,8 +67,8 @@
     eprintln!("Loaded {} ebuilds", results.len());
 
     Ok(results.into_iter().partition_map(|eval| match eval {
-        Ok(details) => Either::Left(details),
-        Err(err) => Either::Right(err),
+        MaybePackageDetails::Ok(details) => Either::Left(details),
+        MaybePackageDetails::Err(err) => Either::Right(err),
     }))
 }
 
diff --git a/portage/bin/alchemist/src/ebuild/mod.rs b/portage/bin/alchemist/src/ebuild/mod.rs
index 6cf1a09..5a6cceb 100644
--- a/portage/bin/alchemist/src/ebuild/mod.rs
+++ b/portage/bin/alchemist/src/ebuild/mod.rs
@@ -8,6 +8,7 @@
 use once_cell::sync::OnceCell;
 use std::{
     collections::{HashMap, HashSet},
+    ops::Deref,
     path::{Path, PathBuf},
     sync::{Arc, Mutex},
 };
@@ -24,7 +25,7 @@
     },
 };
 
-use self::metadata::{CachedEBuildEvaluator, MaybeEBuildMetadata};
+use self::metadata::{CachedEBuildEvaluator, EBuildBasicData, EBuildMetadata, MaybeEBuildMetadata};
 
 /// Parses IUSE defined by ebuild/eclasses and returns as an [IUseMap].
 fn parse_iuse_map(vars: &BashVars) -> Result<IUseMap> {
@@ -44,30 +45,14 @@
         .collect())
 }
 
-type PackageResult = Result<PackageDetails, PackageMetadataError>;
-
-/// Holds the error that occurred when processing the ebuild.
-#[derive(Clone, Debug)]
-pub struct PackageMetadataError {
-    pub repo_name: String,
-    pub package_name: String,
-    pub ebuild: PathBuf,
-    pub version: Version,
-    pub error: String,
-}
-
-#[derive(Clone, Debug)]
+#[derive(Debug)]
 pub struct PackageDetails {
-    pub repo_name: String,
-    pub package_name: String,
-    pub version: Version,
-    pub vars: BashVars,
+    pub metadata: Arc<EBuildMetadata>,
     pub slot: Slot,
     pub use_map: UseMap,
     pub accepted: bool,
     pub stable: bool,
     pub masked: bool,
-    pub ebuild_path: PathBuf,
     pub inherited: HashSet<String>,
     pub inherit_paths: Vec<PathBuf>,
     pub direct_build_target: Option<String>,
@@ -115,6 +100,53 @@
     }
 }
 
+impl Deref for PackageDetails {
+    type Target = EBuildMetadata;
+
+    fn deref(&self) -> &Self::Target {
+        &self.metadata
+    }
+}
+
+/// Represents an error that occurred when loading an ebuild.
+#[derive(Clone, Debug)]
+pub struct PackageLoadError {
+    pub metadata: MaybeEBuildMetadata,
+    pub error: String,
+}
+
+impl Deref for PackageLoadError {
+    type Target = MaybeEBuildMetadata;
+
+    fn deref(&self) -> &Self::Target {
+        &self.metadata
+    }
+}
+
+/// Represents a package, covering both successfully loaded ones and failed ones.
+///
+/// Since this enum is very lightweight (contains [`Arc`] only), you should not wrap it within
+/// reference-counting smart pointers like [`Arc`], but you can just clone it.
+///
+/// While this enum looks very similar to [`Result`], we don't make it a type alias of [`Result`]
+/// to implement a few convenient methods.
+#[derive(Clone, Debug)]
+pub enum MaybePackageDetails {
+    Ok(Arc<PackageDetails>),
+    Err(Arc<PackageLoadError>),
+}
+
+impl Deref for MaybePackageDetails {
+    type Target = EBuildBasicData;
+
+    fn deref(&self) -> &Self::Target {
+        match self {
+            MaybePackageDetails::Ok(details) => details,
+            MaybePackageDetails::Err(error) => error,
+        }
+    }
+}
+
 #[derive(Debug)]
 pub struct PackageLoader {
     evaluator: Arc<CachedEBuildEvaluator>,
@@ -137,7 +169,7 @@
         }
     }
 
-    pub fn load_package(&self, ebuild_path: &Path) -> Result<PackageResult> {
+    pub fn load_package(&self, ebuild_path: &Path) -> Result<MaybePackageDetails> {
         // Drive the ebuild to read its metadata.
         let metadata = self.evaluator.evaluate_metadata(ebuild_path)?;
 
@@ -147,13 +179,10 @@
         let metadata = match metadata {
             MaybeEBuildMetadata::Ok(metadata) => metadata,
             MaybeEBuildMetadata::Err(error) => {
-                return Ok(PackageResult::Err(PackageMetadataError {
-                    repo_name: error.repo_name.clone(),
-                    package_name,
-                    ebuild: ebuild_path.to_owned(),
-                    version: error.version.clone(),
+                return Ok(MaybePackageDetails::Err(Arc::new(PackageLoadError {
                     error: error.error.clone(),
-                }))
+                    metadata: MaybeEBuildMetadata::Err(error),
+                })))
             }
         };
 
@@ -220,11 +249,8 @@
                 }
             });
 
-        Ok(PackageResult::Ok(PackageDetails {
-            repo_name: metadata.repo_name.clone(),
-            package_name,
-            version: metadata.version.clone(),
-            vars: metadata.vars.clone(),
+        Ok(MaybePackageDetails::Ok(Arc::new(PackageDetails {
+            metadata,
             slot,
             use_map,
             accepted,
@@ -232,19 +258,16 @@
             masked,
             inherited,
             inherit_paths,
-            ebuild_path: ebuild_path.to_owned(),
             direct_build_target,
-        }))
+        })))
     }
 }
 
-type CachedPackageResult = std::result::Result<Arc<PackageDetails>, Arc<PackageMetadataError>>;
-
 /// Wraps PackageLoader to cache results.
 #[derive(Debug)]
 pub struct CachedPackageLoader {
     loader: PackageLoader,
-    cache: Mutex<HashMap<PathBuf, Arc<OnceCell<CachedPackageResult>>>>,
+    cache: Mutex<HashMap<PathBuf, Arc<OnceCell<MaybePackageDetails>>>>,
 }
 
 impl CachedPackageLoader {
@@ -255,7 +278,7 @@
         }
     }
 
-    pub fn load_package(&self, ebuild_path: &Path) -> Result<CachedPackageResult> {
+    pub fn load_package(&self, ebuild_path: &Path) -> Result<MaybePackageDetails> {
         let once_cell = {
             let mut cache_guard = self.cache.lock().unwrap();
             cache_guard
@@ -263,14 +286,7 @@
                 .or_default()
                 .clone()
         };
-        let details = once_cell.get_or_try_init(|| -> Result<CachedPackageResult> {
-            match self.loader.load_package(ebuild_path)? {
-                PackageResult::Ok(details) => {
-                    Result::Ok(CachedPackageResult::Ok(Arc::new(details)))
-                }
-                PackageResult::Err(err) => Result::Ok(CachedPackageResult::Err(Arc::new(err))),
-            }
-        })?;
+        let details = once_cell.get_or_try_init(|| self.loader.load_package(ebuild_path))?;
         Ok(details.clone())
     }
 }
diff --git a/portage/bin/alchemist/src/resolver.rs b/portage/bin/alchemist/src/resolver.rs
index 30d9b22..7303a01 100644
--- a/portage/bin/alchemist/src/resolver.rs
+++ b/portage/bin/alchemist/src/resolver.rs
@@ -15,7 +15,7 @@
         package::{PackageAtom, PackageDependencyAtom},
         Predicate,
     },
-    ebuild::{CachedPackageLoader, PackageDetails},
+    ebuild::{CachedPackageLoader, MaybePackageDetails, PackageDetails},
     repository::RepositorySet,
 };
 
@@ -53,9 +53,9 @@
             .map(|ebuild_path| self.loader.load_package(&ebuild_path))
             .filter_map(|result| match result {
                 Ok(eval) => match eval {
-                    Ok(details) => Some(Ok(details)),
+                    MaybePackageDetails::Ok(details) => Some(Ok(details)),
                     // We ignore packages that had metadata evaluation errors.
-                    Err(_) => None,
+                    MaybePackageDetails::Err(_) => None,
                 },
                 Err(e) => Some(Err(e)),
             })
@@ -99,9 +99,9 @@
         let mut matches = Vec::with_capacity(packages.len());
         for eval in packages {
             let details = match eval {
-                Ok(details) => details,
+                MaybePackageDetails::Ok(details) => details,
                 // We ignore packages that had metadata evaluation errors.
-                Err(_) => continue,
+                MaybePackageDetails::Err(_) => continue,
             };
             match atom.package_matches(use_map, &details.as_package_ref()) {
                 Ok(result) => {