buildkit_llb/ops/fs/
mkfile.rs

1use std::collections::HashMap;
2use std::path::{Path, PathBuf};
3
4use buildkit_proto::pb;
5
6use super::path::LayerPath;
7use super::FileOperation;
8
9use crate::serialization::{Context, Result};
10use crate::utils::OutputIdx;
11
12#[derive(Debug)]
13pub struct MakeFileOperation<'a> {
14    path: LayerPath<'a, PathBuf>,
15    output: OutputIdx,
16
17    data: Option<Vec<u8>>,
18
19    description: HashMap<String, String>,
20    caps: HashMap<String, bool>,
21}
22
23impl<'a> MakeFileOperation<'a> {
24    pub(crate) fn new<P>(output: OutputIdx, path: LayerPath<'a, P>) -> Self
25    where
26        P: AsRef<Path>,
27    {
28        let mut caps = HashMap::<String, bool>::new();
29        caps.insert("file.base".into(), true);
30
31        MakeFileOperation {
32            path: path.into_owned(),
33            output,
34
35            data: None,
36
37            caps,
38            description: Default::default(),
39        }
40    }
41
42    pub fn data(mut self, bytes: Vec<u8>) -> Self {
43        self.data = Some(bytes);
44        self
45    }
46
47    pub fn into_operation(self) -> super::sequence::SequenceOperation<'a> {
48        super::sequence::SequenceOperation::new().append(self)
49    }
50}
51
52impl<'a> FileOperation for MakeFileOperation<'a> {
53    fn output(&self) -> i32 {
54        self.output.into()
55    }
56
57    fn serialize_inputs(&self, cx: &mut Context) -> Result<Vec<pb::Input>> {
58        if let LayerPath::Other(ref op, ..) = self.path {
59            let serialized_from_head = cx.register(op.operation())?;
60
61            let inputs = vec![pb::Input {
62                digest: serialized_from_head.digest.clone(),
63                index: op.output().into(),
64            }];
65
66            Ok(inputs)
67        } else {
68            Ok(Vec::with_capacity(0))
69        }
70    }
71
72    fn serialize_action(
73        &self,
74        inputs_count: usize,
75        inputs_offset: usize,
76    ) -> Result<pb::FileAction> {
77        let (src_idx, path) = match self.path {
78            LayerPath::Scratch(ref path) => (-1, path.to_string_lossy().into()),
79            LayerPath::Other(_, ref path) => (inputs_offset as i64, path.to_string_lossy().into()),
80
81            LayerPath::Own(ref output, ref path) => {
82                let output: i64 = output.into();
83
84                (inputs_count as i64 + output, path.to_string_lossy().into())
85            }
86        };
87
88        Ok(pb::FileAction {
89            input: src_idx,
90            secondary_input: -1,
91
92            output: i64::from(self.output()),
93
94            action: Some(pb::file_action::Action::Mkfile(pb::FileActionMkFile {
95                path,
96
97                data: self.data.clone().unwrap_or_else(|| Vec::with_capacity(0)),
98
99                // TODO: make this configurable
100                mode: -1,
101
102                // TODO: make this configurable
103                timestamp: -1,
104
105                // TODO: make this configurable
106                owner: None,
107            })),
108        })
109    }
110}