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.
215 lines
5.6 KiB
Rust
215 lines
5.6 KiB
Rust
3 years ago
|
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<From: Debug, To: Debug> {
|
||
|
source: From,
|
||
|
destination: To,
|
||
|
|
||
|
follow_symlinks: bool,
|
||
|
recursive: bool,
|
||
|
create_path: bool,
|
||
|
wildcard: bool,
|
||
|
|
||
|
description: HashMap<String, String>,
|
||
|
caps: HashMap<String, bool>,
|
||
|
}
|
||
|
|
||
|
type OpWithoutSource = CopyOperation<UnsetPath, UnsetPath>;
|
||
|
type OpWithSource<'a> = CopyOperation<LayerPath<'a, PathBuf>, UnsetPath>;
|
||
|
type OpWithDestination<'a> =
|
||
|
CopyOperation<LayerPath<'a, PathBuf>, (OutputIdx, LayerPath<'a, PathBuf>)>;
|
||
|
|
||
|
impl OpWithoutSource {
|
||
|
pub(crate) fn new() -> OpWithoutSource {
|
||
|
let mut caps = HashMap::<String, bool>::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<P>(self, source: LayerPath<'_, P>) -> OpWithSource
|
||
|
where
|
||
|
P: AsRef<Path>,
|
||
|
{
|
||
|
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<P>(self, output: OutputIdx, destination: LayerPath<'a, P>) -> OpWithDestination<'a>
|
||
|
where
|
||
|
P: AsRef<Path>,
|
||
|
{
|
||
|
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<From, To> CopyOperation<From, To>
|
||
|
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<Vec<pb::Input>> {
|
||
|
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<pb::FileAction> {
|
||
|
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()
|
||
|
})),
|
||
|
})
|
||
|
}
|
||
|
}
|