Skip to main content

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::fuchsia_pkg::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 =
63            Some(cache_packages.iter().map(|pkg| pkg.pinned_fuchsia_url()).collect());
64        self
65    }
66
67    /// Appends the given package set type, path and hash to the anchored packages manifest,
68    /// creating the manifest if it was not already staged to be added to the package.
69    pub fn anchored_package(
70        mut self,
71        package_set_type: AnchoredPackageSetType,
72        path: PackagePath,
73        hash: Hash,
74    ) -> Self {
75        let (name, variant) = path.into_name_and_variant();
76        let pinned_url = PinnedAbsolutePackageUrl::new(
77            DEFAULT_PACKAGE_REPO_URL.parse().unwrap(),
78            name,
79            Some(variant),
80            hash,
81        );
82        self.anchored_packages
83            .get_or_insert_default()
84            .insert(package_set_type, pinned_url)
85            .unwrap();
86        self
87    }
88
89    /// Disable enforcement of executability restrictions for packages that are not base or
90    /// allowlisted.
91    pub fn pkgfs_disable_executability_restrictions(mut self) -> Self {
92        self.pkgfs_disable_executability_restrictions = true;
93        self
94    }
95
96    fn packages_to_entries(pkgs: &[&Package]) -> Vec<(PackagePath, Hash)> {
97        pkgs.iter()
98            .map(|pkg| {
99                (
100                    PackagePath::from_name_and_variant(pkg.name().to_owned(), "0".parse().unwrap()),
101                    *pkg.hash(),
102                )
103            })
104            .collect()
105    }
106
107    /// Build the system_image package.
108    pub fn build(&self) -> impl Future<Output = Package> {
109        let mut builder = PackageBuilder::new("system_image");
110        let mut bytes = vec![];
111
112        StaticPackages::from_iter(self.static_packages.clone().unwrap_or_default())
113            .serialize(&mut bytes)
114            .unwrap();
115        builder = builder.add_resource_at("data/static_packages", bytes.as_slice());
116
117        if let Some(cache_packages) = &self.cache_packages {
118            bytes.clear();
119            let cache_packages = CachePackages::from_entries(cache_packages.clone());
120            cache_packages.serialize(&mut bytes).unwrap();
121            builder = builder.add_resource_at("data/cache_packages.json", bytes.as_slice());
122        }
123
124        if let Some(anchored_packages) = &self.anchored_packages {
125            bytes.clear();
126            anchored_packages.serialize(&mut bytes).unwrap();
127            builder = builder.add_resource_at("data/anchored_packages.json", bytes.as_slice());
128        }
129
130        if self.pkgfs_disable_executability_restrictions {
131            builder = builder
132                .add_resource_at("data/pkgfs_disable_executability_restrictions", &[] as &[u8]);
133        }
134
135        async move { builder.build().await.unwrap() }
136    }
137}