use std::collections::HashMap; use std::fmt::Debug; use std::path::{Path, PathBuf}; use buildkit_proto::pb; use super::path::{LayerPath, UnsetPath}; use super::FileOperation; use crate::serialization::{Context, Result}; use crate::utils::OutputIdx; #[derive(Debug)] pub struct CopyOperation { source: From, destination: To, follow_symlinks: bool, recursive: bool, create_path: bool, wildcard: bool, description: HashMap, caps: HashMap, } type OpWithoutSource = CopyOperation; type OpWithSource<'a> = CopyOperation, UnsetPath>; type OpWithDestination<'a> = CopyOperation, (OutputIdx, LayerPath<'a, PathBuf>)>; impl OpWithoutSource { pub(crate) fn new() -> OpWithoutSource { let mut caps = HashMap::::new(); caps.insert("file.base".into(), true); CopyOperation { source: UnsetPath, destination: UnsetPath, follow_symlinks: false, recursive: false, create_path: false, wildcard: false, caps, description: Default::default(), } } pub fn from

(self, source: LayerPath<'_, P>) -> OpWithSource where P: AsRef, { CopyOperation { source: source.into_owned(), destination: UnsetPath, follow_symlinks: self.follow_symlinks, recursive: self.recursive, create_path: self.create_path, wildcard: self.wildcard, description: self.description, caps: self.caps, } } } impl<'a> OpWithSource<'a> { pub fn to

(self, output: OutputIdx, destination: LayerPath<'a, P>) -> OpWithDestination<'a> where P: AsRef, { CopyOperation { source: self.source, destination: (output, destination.into_owned()), follow_symlinks: self.follow_symlinks, recursive: self.recursive, create_path: self.create_path, wildcard: self.wildcard, description: self.description, caps: self.caps, } } } impl<'a> OpWithDestination<'a> { pub fn into_operation(self) -> super::sequence::SequenceOperation<'a> { super::sequence::SequenceOperation::new().append(self) } } impl CopyOperation where From: Debug, To: Debug, { pub fn follow_symlinks(mut self, value: bool) -> Self { self.follow_symlinks = value; self } pub fn recursive(mut self, value: bool) -> Self { self.recursive = value; self } pub fn create_path(mut self, value: bool) -> Self { self.create_path = value; self } pub fn wildcard(mut self, value: bool) -> Self { self.wildcard = value; self } } impl<'a> FileOperation for OpWithDestination<'a> { fn output(&self) -> i32 { self.destination.0.into() } fn serialize_inputs(&self, cx: &mut Context) -> Result> { let mut inputs = if let LayerPath::Other(ref op, ..) = self.source { let serialized_from_head = cx.register(op.operation())?; vec![pb::Input { digest: serialized_from_head.digest.clone(), index: op.output().into(), }] } else { vec![] }; if let LayerPath::Other(ref op, ..) = self.destination.1 { let serialized_to_head = cx.register(op.operation())?; inputs.push(pb::Input { digest: serialized_to_head.digest.clone(), index: op.output().into(), }); } Ok(inputs) } fn serialize_action( &self, inputs_count: usize, inputs_offset: usize, ) -> Result { let (src_idx, src_offset, src) = match self.source { LayerPath::Scratch(ref path) => (-1, 0, path.to_string_lossy().into()), LayerPath::Other(_, ref path) => { (inputs_offset as i64, 1, path.to_string_lossy().into()) } LayerPath::Own(ref output, ref path) => { let output: i64 = output.into(); ( inputs_count as i64 + output, 0, path.to_string_lossy().into(), ) } }; let (dest_idx, dest) = match self.destination.1 { LayerPath::Scratch(ref path) => (-1, path.to_string_lossy().into()), LayerPath::Other(_, ref path) => ( inputs_offset as i32 + src_offset, path.to_string_lossy().into(), ), LayerPath::Own(ref output, ref path) => { let output: i32 = output.into(); (inputs_count as i32 + output, path.to_string_lossy().into()) } }; Ok(pb::FileAction { input: i64::from(dest_idx), secondary_input: src_idx, output: i64::from(self.output()), action: Some(pb::file_action::Action::Copy(pb::FileActionCopy { src, dest, follow_symlink: self.follow_symlinks, dir_copy_contents: self.recursive, create_dest_path: self.create_path, allow_wildcard: self.wildcard, // TODO: make this configurable mode: -1, // TODO: make this configurable timestamp: -1, ..Default::default() })), }) } }