buildkit_llb/ops/source/
http.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3
4use buildkit_proto::pb::{self, op::Op, OpMetadata, SourceOp};
5
6use crate::ops::{OperationBuilder, SingleBorrowedOutput, SingleOwnedOutput};
7use crate::serialization::{Context, Node, Operation, OperationId, Result};
8use crate::utils::{OperationOutput, OutputIdx};
9
10#[derive(Default, Debug)]
11pub struct HttpSource {
12    id: OperationId,
13    url: String,
14    file_name: Option<String>,
15    description: HashMap<String, String>,
16    ignore_cache: bool,
17}
18
19impl HttpSource {
20    pub(crate) fn new<S>(url: S) -> Self
21    where
22        S: Into<String>,
23    {
24        Self {
25            id: OperationId::default(),
26            url: url.into(),
27            file_name: None,
28            description: Default::default(),
29            ignore_cache: false,
30        }
31    }
32}
33
34impl HttpSource {
35    pub fn with_file_name<S>(mut self, name: S) -> Self
36    where
37        S: Into<String>,
38    {
39        self.file_name = Some(name.into());
40        self
41    }
42}
43
44impl<'a> SingleBorrowedOutput<'a> for HttpSource {
45    fn output(&'a self) -> OperationOutput<'a> {
46        OperationOutput::borrowed(self, OutputIdx(0))
47    }
48}
49
50impl<'a> SingleOwnedOutput<'static> for Arc<HttpSource> {
51    fn output(&self) -> OperationOutput<'static> {
52        OperationOutput::owned(self.clone(), OutputIdx(0))
53    }
54}
55
56impl OperationBuilder<'static> for HttpSource {
57    fn custom_name<S>(mut self, name: S) -> Self
58    where
59        S: Into<String>,
60    {
61        self.description
62            .insert("llb.customname".into(), name.into());
63
64        self
65    }
66
67    fn ignore_cache(mut self, ignore: bool) -> Self {
68        self.ignore_cache = ignore;
69        self
70    }
71}
72
73impl Operation for HttpSource {
74    fn id(&self) -> &OperationId {
75        &self.id
76    }
77
78    fn serialize(&self, _: &mut Context) -> Result<Node> {
79        let mut attrs = HashMap::default();
80
81        if let Some(ref file_name) = self.file_name {
82            attrs.insert("http.filename".into(), file_name.into());
83        }
84
85        let head = pb::Op {
86            op: Some(Op::Source(SourceOp {
87                identifier: self.url.clone(),
88                attrs,
89            })),
90
91            ..Default::default()
92        };
93
94        let metadata = OpMetadata {
95            description: self.description.clone(),
96            ignore_cache: self.ignore_cache,
97
98            ..Default::default()
99        };
100
101        Ok(Node::new(head, metadata))
102    }
103}
104
105#[test]
106fn serialization() {
107    crate::check_op!(
108        HttpSource::new("http://any.url/with/path"),
109        |digest| { "sha256:22ec64461f39dd3b54680fc240b459248b1ced597f113b5d692abe9695860d12" },
110        |description| { vec![] },
111        |caps| { vec![] },
112        |cached_tail| { vec![] },
113        |inputs| { vec![] },
114        |op| {
115            Op::Source(SourceOp {
116                identifier: "http://any.url/with/path".into(),
117                attrs: Default::default(),
118            })
119        },
120    );
121
122    crate::check_op!(
123        HttpSource::new("http://any.url/with/path").custom_name("git custom name"),
124        |digest| { "sha256:22ec64461f39dd3b54680fc240b459248b1ced597f113b5d692abe9695860d12" },
125        |description| { vec![("llb.customname", "git custom name")] },
126        |caps| { vec![] },
127        |cached_tail| { vec![] },
128        |inputs| { vec![] },
129        |op| {
130            Op::Source(SourceOp {
131                identifier: "http://any.url/with/path".into(),
132                attrs: Default::default(),
133            })
134        },
135    );
136
137    crate::check_op!(
138        HttpSource::new("http://any.url/with/path").with_file_name("file.name"),
139        |digest| { "sha256:e1fe6584287dfa2b065ed29fcf4f77bcf86fb54781832d2f45074fa1671df692" },
140        |description| { vec![] },
141        |caps| { vec![] },
142        |cached_tail| { vec![] },
143        |inputs| { vec![] },
144        |op| {
145            Op::Source(SourceOp {
146                identifier: "http://any.url/with/path".into(),
147                attrs: vec![("http.filename".to_string(), "file.name".to_string())]
148                    .into_iter()
149                    .collect(),
150            })
151        },
152    );
153}