omicron_zone_package/input.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use anyhow::Context;
6use camino::{Utf8Path, Utf8PathBuf};
7use serde::{Deserialize, Serialize};
8
9/// A directory that should be added to the target archive
10#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
11pub struct TargetDirectory(pub Utf8PathBuf);
12
13/// A package that should be added to the target archive
14#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
15pub struct TargetPackage(pub Utf8PathBuf);
16
17/// A pair of paths, mapping from a file or directory on the host to the target
18#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
19pub struct MappedPath {
20 /// Source path.
21 pub from: Utf8PathBuf,
22 /// Destination path.
23 pub to: Utf8PathBuf,
24}
25
26/// All possible inputs which are used to construct Omicron packages
27#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
28pub enum BuildInput {
29 /// Adds a single file, which is stored in-memory.
30 ///
31 /// This is mostly used as a way to cache metadata.
32 AddInMemoryFile {
33 dst_path: Utf8PathBuf,
34 contents: String,
35 },
36
37 /// Add a single directory to the target archive.
38 ///
39 /// This directory doesn't need to exist on the build host.
40 AddDirectory(TargetDirectory),
41
42 /// Add a file directly from source to target.
43 AddFile {
44 /// Describes the files being added.
45 mapped_path: MappedPath,
46
47 /// The length of the file.
48 ///
49 /// Q: Is this necessary? Aren't we already storing the file itself,
50 /// making this field redundant?
51 ///
52 /// A: We use it to help caching, on the "known cache miss" case. In
53 /// *most* circumstances where a file has been edited, the length
54 /// changes too. Comparing u64s is significantly faster than hashing,
55 /// in this situation.
56 len: u64,
57 },
58
59 /// Add a dowloaded file from source to target.
60 ///
61 /// This is similar to "AddFile", though it may require downloading an input
62 /// first.
63 AddBlob {
64 path: MappedPath,
65 blob: crate::blob::Source,
66 },
67
68 /// Add a package from source to target.
69 ///
70 /// This is similar to "AddFile", though it requires unpacking the package
71 /// and re-packaging it into the target.
72 AddPackage(TargetPackage),
73}
74
75impl BuildInput {
76 /// If the input has a path on the host machine, return it.
77 pub fn input_path(&self) -> Option<&Utf8Path> {
78 match self {
79 // This file is stored in-memory, it isn't cached.
80 BuildInput::AddInMemoryFile { .. } => None,
81 // This path doesn't need to exist on the host, it's just fabricated
82 // on the target.
83 BuildInput::AddDirectory(_target) => None,
84 BuildInput::AddFile { mapped_path, .. } => Some(&mapped_path.from),
85 BuildInput::AddBlob { path, .. } => Some(&path.from),
86 BuildInput::AddPackage(target_package) => Some(&target_package.0),
87 }
88 }
89
90 pub fn add_file(mapped_path: MappedPath) -> anyhow::Result<Self> {
91 let src = &mapped_path.from;
92 let len = src
93 .metadata()
94 .with_context(|| format!("Failed to get length of {src}"))?
95 .len();
96
97 Ok(Self::AddFile { mapped_path, len })
98 }
99}
100
101/// A ordered collection of build inputs.
102pub struct BuildInputs(pub Vec<BuildInput>);
103
104impl BuildInputs {
105 pub fn new() -> Self {
106 Self(vec![])
107 }
108}
109
110impl Default for BuildInputs {
111 fn default() -> Self {
112 Self::new()
113 }
114}