You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.6 KiB
Rust
141 lines
3.6 KiB
Rust
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
|
|
use buildkit_proto::pb::{self, op::Op};
|
|
|
|
use super::FileOperation;
|
|
|
|
use crate::ops::*;
|
|
use crate::serialization::{Context, Node, Operation, OperationId, Result};
|
|
use crate::utils::{OperationOutput, OutputIdx};
|
|
|
|
#[derive(Debug)]
|
|
pub struct SequenceOperation<'a> {
|
|
id: OperationId,
|
|
inner: Vec<Box<dyn FileOperation + 'a>>,
|
|
|
|
description: HashMap<String, String>,
|
|
caps: HashMap<String, bool>,
|
|
ignore_cache: bool,
|
|
}
|
|
|
|
impl<'a> SequenceOperation<'a> {
|
|
pub(crate) fn new() -> Self {
|
|
let mut caps = HashMap::<String, bool>::new();
|
|
caps.insert("file.base".into(), true);
|
|
|
|
Self {
|
|
id: OperationId::default(),
|
|
inner: vec![],
|
|
|
|
caps,
|
|
description: Default::default(),
|
|
ignore_cache: false,
|
|
}
|
|
}
|
|
|
|
pub fn append<T>(mut self, op: T) -> Self
|
|
where
|
|
T: FileOperation + 'a,
|
|
{
|
|
// TODO: verify no duplicated outputs
|
|
|
|
self.inner.push(Box::new(op));
|
|
self
|
|
}
|
|
|
|
pub fn last_output_index(&self) -> Option<u32> {
|
|
// TODO: make sure the `inner` elements have monotonic indexes
|
|
|
|
self.inner
|
|
.iter()
|
|
.filter(|fs| fs.output() >= 0)
|
|
.last()
|
|
.map(|fs| fs.output() as u32)
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b: 'a> MultiBorrowedOutput<'b> for SequenceOperation<'b> {
|
|
fn output(&'b self, index: u32) -> OperationOutput<'b> {
|
|
// TODO: check if the requested index available.
|
|
OperationOutput::borrowed(self, OutputIdx(index))
|
|
}
|
|
}
|
|
|
|
impl<'a> MultiOwnedOutput<'a> for Arc<SequenceOperation<'a>> {
|
|
fn output(&self, index: u32) -> OperationOutput<'a> {
|
|
// TODO: check if the requested index available.
|
|
OperationOutput::owned(self.clone(), OutputIdx(index))
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b: 'a> MultiBorrowedLastOutput<'b> for SequenceOperation<'b> {
|
|
fn last_output(&'b self) -> Option<OperationOutput<'b>> {
|
|
self.last_output_index().map(|index| self.output(index))
|
|
}
|
|
}
|
|
|
|
impl<'a> MultiOwnedLastOutput<'a> for Arc<SequenceOperation<'a>> {
|
|
fn last_output(&self) -> Option<OperationOutput<'a>> {
|
|
self.last_output_index().map(|index| self.output(index))
|
|
}
|
|
}
|
|
|
|
impl<'a> OperationBuilder<'a> for SequenceOperation<'a> {
|
|
fn custom_name<S>(mut self, name: S) -> Self
|
|
where
|
|
S: Into<String>,
|
|
{
|
|
self.description
|
|
.insert("llb.customname".into(), name.into());
|
|
|
|
self
|
|
}
|
|
|
|
fn ignore_cache(mut self, ignore: bool) -> Self {
|
|
self.ignore_cache = ignore;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<'a> Operation for SequenceOperation<'a> {
|
|
fn id(&self) -> &OperationId {
|
|
&self.id
|
|
}
|
|
|
|
fn serialize(&self, cx: &mut Context) -> Result<Node> {
|
|
let mut inputs = vec![];
|
|
let mut input_offsets = vec![];
|
|
|
|
for item in &self.inner {
|
|
let mut inner_inputs = item.serialize_inputs(cx)?;
|
|
|
|
input_offsets.push(inputs.len());
|
|
inputs.append(&mut inner_inputs);
|
|
}
|
|
|
|
let mut actions = vec![];
|
|
|
|
for (item, offset) in self.inner.iter().zip(input_offsets.into_iter()) {
|
|
actions.push(item.serialize_action(inputs.len(), offset)?);
|
|
}
|
|
|
|
let head = pb::Op {
|
|
inputs,
|
|
op: Some(Op::File(pb::FileOp { actions })),
|
|
|
|
..Default::default()
|
|
};
|
|
|
|
let metadata = pb::OpMetadata {
|
|
description: self.description.clone(),
|
|
caps: self.caps.clone(),
|
|
ignore_cache: self.ignore_cache,
|
|
|
|
..Default::default()
|
|
};
|
|
|
|
Ok(Node::new(head, metadata))
|
|
}
|
|
}
|