fuchsia_pkg_testing/
system_image.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{Package, PackageBuilder};
6use fuchsia_merkle::Hash;
7use fuchsia_pkg::PackagePath;
8use fuchsia_pkg::package_sets::AnchoredPackageSetType;
9use fuchsia_url::PinnedAbsolutePackageUrl;
10use std::future::Future;
11use system_image::{AnchoredPackages, CachePackages, StaticPackages};
12
13const DEFAULT_PACKAGE_REPO_URL: &str = "fuchsia-pkg://fuchsia.com";
14
15/// Builds a system_image package.
16#[derive(Default)]
17pub struct SystemImageBuilder {
18    static_packages: Option<Vec<(PackagePath, Hash)>>,
19    cache_packages: Option<Vec<PinnedAbsolutePackageUrl>>,
20    anchored_packages: Option<AnchoredPackages>,
21    pkgfs_disable_executability_restrictions: bool,
22}
23
24impl SystemImageBuilder {
25    /// Returns an empty `SystemImageBuilder` configured with no static or cache package.
26    pub fn new() -> Self {
27        Self::default()
28    }
29
30    /// Appends the given path and hash to the static packages manifest.
31    pub fn static_package(mut self, path: PackagePath, hash: Hash) -> Self {
32        self.static_packages.get_or_insert_with(Vec::new).push((path, hash));
33        self
34    }
35
36    /// Use the supplied static_packages with the system image. Call at most once and not after
37    /// calling [`Self::static_package`].
38    pub fn static_packages(mut self, static_packages: &[&Package]) -> Self {
39        assert_eq!(self.static_packages, None);
40        self.static_packages = Some(Self::packages_to_entries(static_packages));
41        self
42    }
43
44    /// Appends the given path and hash to the cache packages manifest, creating the manifest if it
45    /// was not already staged to be added to the package.
46    pub fn cache_package(mut self, path: PackagePath, hash: Hash) -> Self {
47        let (name, variant) = path.into_name_and_variant();
48        let pinned_url = PinnedAbsolutePackageUrl::new(
49            DEFAULT_PACKAGE_REPO_URL.parse().unwrap(),
50            name,
51            Some(variant),
52            hash,
53        );
54        self.cache_packages.get_or_insert_with(Vec::new).push(pinned_url);
55        self
56    }
57
58    /// Use the supplied cache_packages with the system image. Call at most once and not after
59    /// calling [`Self::cache_package`].
60    pub fn cache_packages(mut self, cache_packages: &[&Package]) -> Self {
61        assert_eq!(self.cache_packages, None);
62        self.cache_packages = Some(cache_packages.iter().map(|pkg| pkg.fuchsia_url()).collect());
63        self
64    }
65
66    /// Appends the given package set type, path and hash to the anchored packages manifest,
67    /// creating the manifest if it was not already staged to be added to the package.
68    pub fn anchored_package(
69        mut self,
70        package_set_type: AnchoredPackageSetType,
71        path: PackagePath,
72        hash: Hash,
73    ) -> Self {
74        let (name, variant) = path.into_name_and_variant();
75        let pinned_url = PinnedAbsolutePackageUrl::new(
76            DEFAULT_PACKAGE_REPO_URL.parse().unwrap(),
77            name,
78            Some(variant),
79            hash,
80        );
81        self.anchored_packages
82            .get_or_insert_default()
83            .insert(package_set_type, pinned_url)
84            .unwrap();
85        self
86    }
87
88    /// Disable enforcement of executability restrictions for packages that are not base or
89    /// allowlisted.
90    pub fn pkgfs_disable_executability_restrictions(mut self) -> Self {
91        self.pkgfs_disable_executability_restrictions = true;
92        self
93    }
94
95    fn packages_to_entries(pkgs: &[&Package]) -> Vec<(PackagePath, Hash)> {
96        pkgs.iter()
97            .map(|pkg| {
98                (
99                    PackagePath::from_name_and_variant(pkg.name().to_owned(), "0".parse().unwrap()),
100                    *pkg.hash(),
101                )
102            })
103            .collect()
104    }
105
106    /// Build the system_image package.
107    pub fn build(&self) -> impl Future<Output = Package> {
108        let mut builder = PackageBuilder::new("system_image");
109        let mut bytes = vec![];
110
111        StaticPackages::from_entries(self.static_packages.clone().unwrap_or_default())
112            .serialize(&mut bytes)
113            .unwrap();
114        builder = builder.add_resource_at("data/static_packages", bytes.as_slice());
115
116        if let Some(cache_packages) = &self.cache_packages {
117            bytes.clear();
118            let cache_packages = CachePackages::from_entries(cache_packages.clone());
119            cache_packages.serialize(&mut bytes).unwrap();
120            builder = builder.add_resource_at("data/cache_packages.json", bytes.as_slice());
121        }
122
123        if let Some(anchored_packages) = &self.anchored_packages {
124            bytes.clear();
125            anchored_packages.serialize(&mut bytes).unwrap();
126            builder = builder.add_resource_at("data/anchored_packages.json", bytes.as_slice());
127        }
128
129        if self.pkgfs_disable_executability_restrictions {
130            builder = builder
131                .add_resource_at("data/pkgfs_disable_executability_restrictions", &[] as &[u8]);
132        }
133
134        async move { builder.build().await.unwrap() }
135    }
136}