elfpak_core/plan/
model.rs1use crate::{
4 elf::Architecture,
5 graph::{DependencyGraph, Digest},
6 policy::{DependencyPolicy, Preset, RuntimeFeature, RuntimePolicy},
7};
8use std::path::{Path, PathBuf};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11pub enum PlannedFileKind {
12 Directory,
13 Symlink,
14 Executable,
15 Interpreter,
16 SharedObject,
17 CertificateBundle,
18 RuntimeConfig,
19 ApplicationData,
20}
21
22impl PlannedFileKind {
23 pub fn as_str(&self) -> &'static str {
24 match self {
25 PlannedFileKind::Directory => "directory",
26 PlannedFileKind::Symlink => "symlink",
27 PlannedFileKind::Executable => "executable",
28 PlannedFileKind::Interpreter => "interpreter",
29 PlannedFileKind::SharedObject => "shared-object",
30 PlannedFileKind::CertificateBundle => "certificate-bundle",
31 PlannedFileKind::RuntimeConfig => "runtime-config",
32 PlannedFileKind::ApplicationData => "application-data",
33 }
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub enum InclusionReason {
39 Application,
40 Interpreter,
41 NeededBy { binary: PathBuf, soname: String },
42 RuntimePolicy { feature: RuntimeFeature },
43 ExplicitInclude,
44}
45
46#[derive(Debug, Clone)]
48pub struct PlannedFile {
49 pub(crate) source: Option<PathBuf>,
51 pub(crate) destination: PathBuf,
53 pub(crate) kind: PlannedFileKind,
54 pub(crate) reason: InclusionReason,
55 pub(crate) mode: u32,
56 pub(crate) size: u64,
57 pub(crate) sha256: Option<Digest>,
58 pub(crate) link_target: Option<PathBuf>,
60 pub(crate) content: Option<Vec<u8>>,
62}
63
64impl PlannedFile {
65 pub fn source(&self) -> Option<&Path> {
66 self.source.as_deref()
67 }
68
69 pub fn destination(&self) -> &Path {
70 &self.destination
71 }
72
73 pub fn kind(&self) -> PlannedFileKind {
74 self.kind
75 }
76
77 pub fn reason(&self) -> &InclusionReason {
78 &self.reason
79 }
80
81 pub fn mode(&self) -> u32 {
82 self.mode
83 }
84
85 pub fn size(&self) -> u64 {
86 self.size
87 }
88
89 pub fn sha256(&self) -> Option<&Digest> {
90 self.sha256.as_ref()
91 }
92
93 pub fn link_target(&self) -> Option<&Path> {
94 self.link_target.as_deref()
95 }
96
97 pub fn content(&self) -> Option<&[u8]> {
98 self.content.as_deref()
99 }
100
101 pub(crate) fn assert_well_formed(&self) {
104 assert!(self.destination.is_absolute());
105 assert!(self.mode <= 0o7777);
106
107 match self.kind {
108 PlannedFileKind::Directory => {
109 assert!(self.source.is_none());
110 assert!(self.link_target.is_none());
111 assert!(self.content.is_none());
112 assert!(self.sha256.is_none());
113 assert_eq!(self.size, 0);
114 }
115 PlannedFileKind::Symlink => {
116 assert!(self.source.is_none());
117 assert!(self.link_target.is_some());
118 assert!(self.content.is_none());
119 assert!(self.sha256.is_none());
120 assert_eq!(self.size, 0);
121 }
122 _ => {
123 assert!(self.link_target.is_none());
124 assert_ne!(self.source.is_some(), self.content.is_some());
125 assert!(self.sha256.as_ref().is_some_and(Digest::is_well_formed));
126 if let Some(content) = &self.content {
127 assert_eq!(self.size, content.len() as u64);
128 }
129 }
130 }
131 }
132}
133
134#[derive(Debug, Clone)]
135pub struct BundlePlan {
136 pub(crate) executable: PlannedFile,
137 pub(crate) files: Vec<PlannedFile>,
139 pub(crate) graph: DependencyGraph,
140 pub(crate) architecture: Architecture,
141 pub(crate) preset: Option<Preset>,
143 pub(crate) runtime_policy: RuntimePolicy,
145 pub(crate) dependency_policy: DependencyPolicy,
146 pub(crate) interpreter: Option<PathBuf>,
148 pub(crate) interpreter_resolved: Option<PathBuf>,
150 pub(crate) warnings: Vec<Warning>,
151}
152
153impl BundlePlan {
154 pub fn executable(&self) -> &PlannedFile {
155 &self.executable
156 }
157
158 pub fn files(&self) -> &[PlannedFile] {
159 &self.files
160 }
161
162 pub fn graph(&self) -> &DependencyGraph {
163 &self.graph
164 }
165
166 pub fn architecture(&self) -> Architecture {
167 self.architecture
168 }
169
170 pub fn preset(&self) -> Option<Preset> {
171 self.preset
172 }
173
174 pub fn runtime_policy(&self) -> &RuntimePolicy {
175 &self.runtime_policy
176 }
177
178 pub fn dependency_policy(&self) -> &DependencyPolicy {
179 &self.dependency_policy
180 }
181
182 pub fn interpreter(&self) -> Option<&Path> {
183 self.interpreter.as_deref()
184 }
185
186 pub fn interpreter_resolved(&self) -> Option<&Path> {
187 self.interpreter_resolved.as_deref()
188 }
189
190 pub fn warnings(&self) -> &[Warning] {
191 &self.warnings
192 }
193
194 pub fn total_size(&self) -> u64 {
195 self.files.iter().map(|file| file.size).sum()
196 }
197
198 pub fn files_of_kind(&self, kind: PlannedFileKind) -> impl Iterator<Item = &PlannedFile> {
199 self.files.iter().filter(move |file| file.kind == kind)
200 }
201}
202
203#[derive(Debug, Clone)]
204pub struct Warning {
205 pub code: &'static str,
206 pub message: String,
207 pub details: Vec<String>,
208}